尾递归栈溢出

时间:2011-09-03 17:21:41

标签: recursion tail-recursion

据我所知,尾递归函数在最后一步调用自身(如return语句)但是,函数的第一个实例在所有其他实例都被终止之前不会终止,因此我们得到达到多个实例后堆栈溢出。鉴于递归是最后一步,有没有办法在下一个实例期间或之前终止前一个实例?如果实例的唯一目的是调用下一个实例,那么就没有理由将它存在于内存中,对吗?

2 个答案:

答案 0 :(得分:2)

是的,一些编译器会优化尾递归,这样就不需要额外的堆栈空间。例如,让我们看看这个示例C函数:

int braindeadrecursion(int n)
{
  if (n == 0)
    return 1;

  return braindeadrecursion(n - 1);
}

这个功能非常简单;它只返回1.没有优化,clang在我的机器上生成的代码如下所示:

_braindeadrecursion:
00  pushq   %rbp
01  movq    %rsp,%rbp
04  subq    $0x10,%rsp
08  movl    %edi,0xf8(%rbp)
0b  movl    0xf8(%rbp),%eax
0e  cmpl    $_braindeadrecursion,%eax
11  jne 0x0000001c
13  movl    $0x00000001,0xfc(%rbp)
1a  jmp 0x0000002e
1c  movl    0xf8(%rbp),%eax
1f  subl    $0x01,%eax
22  movl    %eax,%edi
24  callq   _braindeadrecursion
29  movl    %eax,%ecx
2b  movl    %ecx,0xfc(%rbp)
2e  movl    0xfc(%rbp),%eax
31  addq    $0x10,%rsp
35  popq    %rbp
36  ret

如您所见,递归调用位于0x24处。现在,让我们尝试更高的优化:

_braindeadrecursion:
00  pushq   %rbp
01  movq    %rsp,%rbp
04  movl    $0x00000001,%eax
09  popq    %rbp
0a  ret

现在,看看那个 - 根本没有递归!这个例子非常简单,但优化仍然可以在更复杂的尾递归情况下进行。

答案 1 :(得分:1)

或者:   - 你可以增加堆栈大小或   - 不要使用递归,而是使用某种循环。