【问题标题】:Can tail recursion support shorten the stack for other function calls?尾递归支持可以缩短其他函数调用的堆栈吗?
【发布时间】:2013-09-06 18:17:42
【问题描述】:

支持尾递归的语言能否将相同的技术应用于非递归函数调用?

例如,如果函数foo 所做的最后一件事是返回调用bar 的值,那么语言是否会丢弃foo 的堆栈帧?是否有任何已知的语言可以真正做到这一点?

【问题讨论】:

  • 我在考虑这个是因为 Ruby 的 Rack 库(尽管大多数 Ruby 实现不支持尾递归);通常 Rack 中间件的最后一个动作是调用下一个中间件,如果可以释放该内存就好了。
  • 我会说这取决于编译器和语言。但是如果被调用的函数都是结束递归的。我猜,编译器可以内联代码。

标签: recursion tail-recursion


【解决方案1】:

Erlang does:

这里看到的尾递归不会使内存增长,因为当 虚拟机看到一个在尾部位置调用自身的函数 (函数中要计算的最后一个表达式),它消除了 当前堆栈帧。这称为尾调用优化 (TCO) 和 它是一种更通用的优化的特例,名为 Last Call 优化 (LCO)。

每当函数中要计算的最后一个表达式时,都会执行 LCO body 是另一个函数调用。当这种情况发生时,与 TCO 一样, Erlang VM 避免存储堆栈帧。因此尾递归是 也可以在多个功能之间。例如,链 函数 a() -> b()。 b() -> c()。 c() -> a()。将有效地创造 由于 LCO 避免溢出,因此不会耗尽内存的无限循环 堆栈。这个原则,结合我们对蓄电池的使用是 是什么让尾递归有用。

【讨论】:

    【解决方案2】:

    是的,它可以。例如,考虑以下 C 代码:

    int f();
    int g() { return f(); }
    

    当我在x86-64 上使用gcc 4.6.3-O3 编译它时,我得到g() 的以下程序集:

    g:
            xorl    %eax, %eax
            jmp     f              ; <==== unconditional jump to f
    

    【讨论】:

    • 太棒了!感谢您提供具体示例。
    猜你喜欢
    • 2019-09-30
    • 1970-01-01
    • 2020-03-06
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 2017-04-26
    相关资源
    最近更新 更多