为什么无限recursion会导致seg错误

为什么无限recursion会导致seg错误? 为什么堆栈溢出导致seg故障。 我正在寻找详细的解释。

int f() { f(); } int main() { f(); } 

Solutions Collecting From Web of "为什么无限recursion会导致seg错误"

每次调用f()时,都会增加堆栈的大小 – 这是存储返回地址的地方,所以当f()完成时程序知道去哪里。 由于你永远不会退出f(),所以堆栈每次调用至少会增加一个返回地址。 一旦堆栈段满了,就会出现段错误。 每个操作系统都会得到相似的结果。

分段错误是您的程序尝试访问不允许访问的内存位置时的一种情况。 无限递归导致您的堆栈增长。 并成长。 并成长。 最终,它会成长到一个点,当它将溢出到一个内存区域,您的程序被禁止访问的操作系统。 这是当你得到分段错误。

您的系统资源是有限的。 他们是有限的。 即使你的系统在整个地球上拥有最多的内存和存储空间,无限远比你拥有的还要多。 记住,现在。

做“无数次”的唯一方法就是“忘记”以前的信息。 也就是说,你必须“忘记”以前做过的事情。 否则,你必须记住之前发生的事情,并且需要一种或另一种形式的存储(缓存,内存,磁盘空间,把东西写在纸上……) – 这是不可避免的。 如果你正在存储的东西,你有一个有限的空间可用。 回想一下,无限的是比你有更大的方式。 如果您尝试存储无限量的信息,则将耗尽存储空间。

当你使用递归的时候,你隐式地把每个递归调用的信息存储起来。 因此,如果你试图做无限次的拍摄,那么在某些时候你会浪费你的存储空间。 这种情况下的存储空间是堆栈。 堆栈是一块有限的内存。 当你使用它并尝试访问超出你所拥有的,系统将产生一个异常,如果它尝试访问的内存被写保护,则可能最终导致seg故障。 如果没有写保护,它将继续进行,覆盖神知道什么,直到它试图写入不存在的内存,或者试图写入其他一些写保护的内存,或者直到它破坏你的代码(在内存中)。

这仍然是一个stackoverflow 😉

问题在于,C运行库不像其他托管语言那样提供“工具化”(例如Java,Python等),因此在为栈指定的空间之外进行编写而不是引发详细的异常只会引发较低级别的错误,通用名称为“分段错误”。

这是出于性能的原因,因为这些内存访问看门狗可以在硬件支持的帮助下设置很少或没有开销; 现在我不记得确切的细节,但通常是通过标记MMU页表或大部分已过时的段偏移寄存器来完成的。

AFAIK:堆栈的末尾受到进程无法访问的地址的保护。 这可以防止堆栈扩展到分配的数据结构上,并且比显式检查堆栈大小更有效,因为无论如何您都必须检查内存保护。

程序copunter或指令指针是一个寄存器,它包含下一条要执行的指令的值。 在函数调用中,程序计数器的当前值被压入堆栈,然后程序计数器指向函数的第一条指令。 从该函数返回之后,旧值被重新分配给程序计数器。 在无限递归中,这个值被一次又一次地推送并导致堆栈溢出。

这和缓冲区溢出本质上是一样的。 操作系统为堆栈分配一个固定数量的内存,当你用完(堆栈溢出),你会得到未定义的行为,在这种情况下,这意味着一个SIGSEGV。

基本思路:

 int stack[A_LOT]; int rsp=0; void call(Func_p fn) { stack[rsp++] = rip; rip = fn; } void retn() { rip = stack[--rsp]; } /*recurse*/ for(;;){call(somefunc);} 

最终rsp会移动到堆栈的末端,并尝试将下一个返回地址放入未分配的存储区和您的程序barfs中。 显然,真正的系统比这个复杂得多,但是可以(并且已经)占用了几本大书。

在“低”级别,堆栈通过指针(堆栈指针)“保持”,保存在处理器寄存器中。 这个寄存器指向内存,因为堆栈毕竟是内存。 当您在堆栈中压入值时,它的“值”会减少(堆栈指针从较高地址移动到较低地址)。 每次你输入一个函数的时候,一些空间被从栈中取出(局部变量)。 此外,在许多体系结构中,对子例程的调用会将堆栈上的返回值压入(如果处理器没有特殊的寄存器堆栈指针,则可能会使用“普通”寄存器,因为即使子程序可以使用,堆栈也是有用的被其他机制调用),这样堆栈至少会被指针的大小(比如说4或8字节)所缩小。

在一个无限递归循环中,在最好的情况下只有返回值会导致堆栈递减…直到指向程序无法访问的内存。 你会看到分段故障问题。

你可能会觉得这个页面很有趣。