为什么这段代码在java中没有内存,而在c中没有?

Gur*_*lki 9 c java programming-languages

在java或c中,我可以编写一个类似的函数

fun(){
  fun();
}
Run Code Online (Sandbox Code Playgroud)

(忽略语法细节)

在java中,我得到了OutOfMemory异常,但是在C(也许还有其他一些语言)中它似乎永远运行,好像它是一个无限循环.为什么我不在这里得到OutOfMemory错误?

RTB*_*ard 19

由于你的函数是尾递归的一个例子,所以很可能,C编译器正在优化迭代的递归,导致它无限循环而不会崩溃.


Mar*_*ger 12

其他的回答是正确的,有一些编译器魔法将尾递归转换为迭代,尽管它取决于编译器的优化设置.例如,在gcc中,如果我们编译gcc -S -O1 someFile.c(给定你的代码),我们得到以下生成的程序集:

fun:
.LFB2:
        pushq   %rbp
.LCFI0:
        movq    %rsp, %rbp
.LCFI1:
        movl    $0, %eax
        call    fun
        leave
        ret
.LFE2:
        .size   fun, .-fun
Run Code Online (Sandbox Code Playgroud)

所以你可以看到,它仍然使用call/leave/ret指令来执行实际的函数调用,这会终止进程.一旦你开始进一步优化gcc -S -O2 someFile.c我们开始获得魔力:

fun:
.LFB24:
        .p2align 4,,10
        .p2align 3
.L2:
        jmp     .L2
.LFE24:    
        .size   fun, .-fun
        .p2align 4,,15
Run Code Online (Sandbox Code Playgroud)

这取决于您的编译器和编译器设置,因此有助于成为他们的朋友.


Jar*_*Par 9

原因是C编译器可能将其视为尾部重用调用,从而避免构建用于执行函数的堆栈.由于没有为调用构建堆栈,因此它从递归变为简单的无限循环执行.您可以强制它通过使其头部递归来构建堆栈

int fun() { 1 + fun(); }
Run Code Online (Sandbox Code Playgroud)