据我所知,尾递归函数在最后一步调用自己(如return语句),但是,函数的第一个实例不会终止,直到所有其他实例都终止,因此在达到多个实例后我们会发生堆栈溢出。鉴于递归是最后一步,有什么办法在下一个实例期间或之前终止前一个实例吗?如果一个实例的唯一目的是调用下一个实例,那么没有理由将它存放在内存中,对吧?尾递归堆栈溢出
Q
尾递归堆栈溢出
2
A
回答
2
是的,一些编译器会优化尾递归,因此它不需要额外的堆栈空间。例如,让我们看一下这个示例的C函数:
int braindeadrecursion(int n)
{
if (n == 0)
return 1;
return braindeadrecursion(n - 1);
}
这个函数很简单;它只是返回1.如果没有优化,铛产生我的机器上的代码看起来像这样:
_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. 堆栈溢出与尾递归
- 2. 试图防止堆栈溢出与尾递归
- 3. scala中没有尾递归优化时堆栈溢出?
- 4. 递归方法堆栈溢出错误
- 5. 堆栈溢出和递归方法
- 6. 递归java堆栈溢出错误
- 7. 使用递归溢出堆栈
- 8. 如何避免递归堆栈溢出?
- 9. 递归方法中的堆栈溢出
- 10. 递归函数堆栈溢出
- 11. ColdFusion:递归太深;堆栈溢出
- 12. 递归求和堆栈溢出
- 13. 为什么尾部递归Collatz猜想会导致Scheme中堆栈溢出?
- 14. 堆栈溢出
- 15. 归并排序导致堆栈溢出
- 16. 无限递归函数 - >堆栈溢出错误
- 17. 将递归函数中的setTimeOut函数导致堆栈溢出?
- 18. 可以使用“递归”回调堆栈溢出吗?
- 19. Haskell递归函数没有堆栈溢出
- 20. 如何避免深层递归中的堆栈溢出
- 21. 从这个递归方法获取堆栈溢出?
- 22. 导致堆栈溢出的递归函数
- 23. Lisp中递归函数调用的堆栈溢出
- 24. 在IE递归堆栈溢出 - > window.frames不等于自己
- 25. 函数与递归导致堆栈溢出
- 26. Java堆栈溢出,因为递归方法调用
- 27. 递归调用导致堆栈溢出异常
- 28. 这个递归程序堆栈溢出错误? - C++
- 29. Java递归数独求解器中的堆栈溢出错误
- 30. 在递归C++函数中捕获“堆栈溢出”异常
我不确定这是否回答了这个问题,但是当我们处理它时,还有其他选择:切换到优化尾部调用的实现(或仅使用需要TCO的语言);使用[trampolining](http://en.wikipedia.org/wiki/Trampoline_%28computers%29#High_Level_Programming);切换到堆上动态调整大小的堆栈,而不是使用硬件堆栈(也许这就是你的意思是“不使用递归”,但我认为它是“切换到等价的迭代算法”)。 – delnan