int main(){
    while(1)
    {
        //code
    }
    return 0;
}

这是一个无限循环,但这会导致系统崩溃吗?
它的表现如何?
我想它会吃掉所有的堆栈段。

最佳答案

这是一个无限循环
它是。我注意到一个好的现代C编译器会给你一个警告。
但这会导致系统崩溃吗?
不,不会的。
如果它是一个userland进程,它不会导致“系统”(内核)崩溃,因为它不会损坏或滥用内核资源。
你所发布的代码也不会导致进程崩溃,因为代码中也没有任何非法或未定义的内容(它只是不会做任何有用的事情)。
基本上,这(如果编译时没有优化):

#    Instruction
1    main:
2        push rbp        ; `int main` function prologue
3        mov  rbp, rsp   ;
4    .loop:
5        jmp  .loop      ; Jump to right before this instruction

您可以使用像godbolt.org这样的编译器输出资源管理器站点看到这一点:https://godbolt.org/z/BMzh7i-注意堆栈指针没有更改(在rsp-忽略函数序言中的mov,这与while循环无关)
这是怎么表现的?
它将被编译为程序集代码中的一个无条件分支,该分支可以无限跳转。(它不会导致系统挂起,因为操作系统控制抢占式多任务中断计时器处理程序)。
我在想-它会吃掉所有的堆栈段。
这不会是因为您发布的代码不会增加堆栈指针(例如,通过在循环内的堆栈上分配任何内容而不减少堆栈指针,或通过在循环内进行函数调用而不弹出被调用函数的帧-如果使用错误的调用约定,则会发生这种情况,但这是一个高级主题)。
如果…怎么办。。。?
如果在while循环中有一个局部变量,这实际上不会导致每次迭代的分配,因为上一次迭代的值不再可访问-所以这。。。
while( 1 ) {
    int foo;
    int ok = fscanf( fd, "%d", &foo );
    if( !ok ) break;
}

……相当于:
int foo;
int ok;
while( 1 ) {
    ok = fscanf( fd, "%d", &foo );
    if( !ok ) break;
}

(这也是为什么非常古老的编程语言常常让你在函数开始时声明所有的局部变量,而不是允许在函数内部声明-它们不再是因为谢天谢地,语言设计者现在比过去更关心语言的人类工程学)。
……但是。。。
一般来说,不调用malloc()就不要调用free()(或者更一般地说:不释放资源就不要获取资源),因此这段代码最终会导致程序内存不足:
while( 1 ) {
    void* ptr = malloc( 1024 )
}

……但这不会:
while( 1 ) {
    void* ptr = malloc( 1024 );
    if( ptr ) free( ptr );
}

(好吧,它可能会耗尽内存due to heap fragmentation这取决于malloc实现的好坏)
别忘了递归
C使直接操作堆栈变得异常困难(例如,尾调用优化要求编译器将其作为优化处理:不幸的是,您不能使用C语言功能强制执行尾调用返回)-因此(据我所知),您可以吹堆栈的主要方法只有两种:
溢出堆栈的主要方法是在不弹出堆栈帧的情况下推送更多的堆栈帧,这可以通过无限递归函数调用(无尾调用优化)来实现。
……或者做一些愚蠢和/或愚蠢的事情,例如使用alloca(例如malloc,但在堆栈上分配内存:但不告诉您是否失败)。

关于c - 无限while循环会导致系统崩溃吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57851267/

10-11 18:12