操作系统到底发生了什么?对于递归函数,可能是堆栈溢出和while(1)?如果我错了,请纠正我?
答案 0 :(得分:14)
递归函数会重复调用自身。无限循环将继续重复执行相同的代码。虽然这听起来非常相似,但实际效果却截然不同。每次调用方法时,变量都会被压入堆栈。当然,这意味着函数可以递归的次数存在固有的限制。因此,当你的无限循环将永远执行时,实际中的递归函数最终会耗尽堆栈空间,应用程序可能会停止运行。
答案 1 :(得分:8)
递归函数调用自身,将参数压入堆栈。这可能会永远持续下去,最终导致堆栈溢出。一些编译器可以优化它,基本上将递归函数转换为while循环 - 这称为尾递归。
while循环将简单地返回到顶部并再次重复使用相同的空间,因此它可以永远运行(至少在电源耗尽之前: - ))
答案 2 :(得分:3)
递归函数不断调用自身,而无限循环不断重复相同的代码块。
调用函数时,必须保留一些存储空间以将其返回值存储在function call stack上。因此,给定足够的函数递归调用,堆栈空间将耗尽并导致堆栈溢出。
考虑
#include <stdlib.h>
#include <stdio.h>
int somefunc(int x) {
printf("%d\n", x);
return somefunc(rand());
}
int main(void) {
return somefunc(0);
}
上述程序最终将终止或造成严重损害,而不是
int somefunc(int x) {
return printf("%d\n", x);
}
int main(void) {
while ( 1 ) {
somefunc(rand());
}
return 0;
}
这将很快运行,直到用户导致终止(通过按 CTRL-C 或关闭计算机。)
答案 3 :(得分:3)
递归函数可以根据其编码方式结束。当然,它不需要以堆栈溢出结束。如果它有中断或返回,while(1)
循环也可以结束。
答案 4 :(得分:1)
递归函数有一个子句,它不调用自身,意味着它结束。
答案 5 :(得分:1)
在'while(1)'无限循环中,将为堆栈帧分配堆栈空间(有关函数返回时返回的位置的信息),并且将分配在同一函数中声明的任何局部变量无论循环执行多少次迭代,都会在堆栈上执行一次。
因此,对于1000000次迭代, 堆栈空间将是sizeof(堆栈帧)+ sizeof(任何局部变量)
因此,如果堆栈帧为16bytes且int为4bytes,则该函数将在堆栈上分配20bytes。
然而,递归函数将在堆栈上为堆栈帧分配空间(有关要返回的函数的信息)以及每次函数调用自身时的任何局部变量。
因此,对于1000000次迭代, 堆栈空间将是(sizeof(堆栈帧)+ sizeof(任何局部变量))* 100000
所以(使用以前的尺寸)20bytes * 1000000 == 20000000bytes ==(约)19MB
答案 6 :(得分:0)
函数推送返回(在内存中从下一个递归函数被调用的位置)堆栈上的地址并跳转到内存中的位置(到递归函数)。 虽然不需要存储ret地址,因为它只会在开头跳转。
答案 7 :(得分:0)
调用函数时,会为堆栈分配一些内存。它使 : - 传递给函数的参数值 - 返回地址 - 内存中的地址,在函数返回后执行将返回 - 局部变量 - 依赖于实施的其他事项
因此,递归函数中的每个函数调用都会分配内存。所以你必须在设计时小心。
在while(1)的情况下 - 执行具有无限循环的程序的过程,如while(1){;} 只重复一些命令。在操作系统中保持这样的进程处于运行状态,这只占用CPU时间和一些内存。
答案 8 :(得分:0)
对于简单代码和良好的编译器没有区别,但对于具有非终止递归函数的天真编译器,您将耗尽堆栈空间,称为堆栈溢出。
关于发生的问题:在堆栈溢出中:堆栈被映射到一个位置或内存(每个进程),旁边有未分配的内存。堆栈用于存储本地函数值,当前函数返回地址也放在堆栈中,然后传递给下一个函数的值放在堆栈上。因此,为每个函数调用消耗堆栈。因此,当CPU尝试访问内存通过分配空间的末尾时,会导致内存访问异常,并将其解释为堆栈溢出。
暂时(1)操作系统行为取决于操作系统使用的多任务处理行为。对于先发制人的系统(例如Window NT和更新版本),它只是看到你的进程有很多工作要做,但是如果它有UI并且你没有回应它发送给你的窗口消息,你会发现获得经典的“此应用程序似乎已停止响应”消息。
在哪里 - 好像你有一个非先发制人的操作系统然后它会挂起,如果你不将控制权交还给操作系统,因此在Windows 3.1天内,打印机驱动程序会在打印时冻结整个系统。惠普司机也做到了。
在嵌入式系统上,为避免软件锁定,它们通常有一个称为看门狗定时器的硬件定时器,如果不是每秒“发痒”,将重启系统。从而防止系统保持在锁定状态。
答案 9 :(得分:0)
while (1)
不会创建新的评估上下文,递归(除非被编译器优化)。这意味着几件事:
while (1)
退出return
是微不足道的,但return
仅在递归时退出当前上下文。完全退出多重嵌套上下文并不是一件容易的事。