使用尾递归时内存泄漏

Memory leak while using tail-recursion

假设我有这个假设函数(在 javascript 中):

function paginationRecursive(results) {
  let intermediate = retrieveNextPage();
  results = results.concat(intermediate)
  if (haveAllResults()) return results;
  return paginationRecursive(results);
}

intermediate 的每个值是否会保留在内存中,直到整个递归处理完成,从而每次递归调用都会增加内存使用量?或者 engine/gc 是否足够聪明,可以在我们调用 "deeper" 时随时释放此内存,因为它知道该变量将永远不会被再次使用?

可能是引擎特定的(例如V8, SpiderMonkey, Chakra, etc.)所以为了让这个问题不宽泛,我更愿意知道 V8 引擎的答案。

我认为截至目前,答案是 "the intermediate variable should be released, but it won't be"。

ES6 确实谈到 tail-position calls 甚至需要优化:

A tail position call must either release any transient internal resources associated with the currently executing function execution context before invoking the target function or reuse those resources in support of the target function.

JS 中 TCO(tail-call 优化)的一个不错的概述是 http://2ality.com/2015/06/tail-call-optimization.html

综上所述,该页面链接到此 table 表明几乎没有运行时实际支持它:https://kangax.github.io/compat-table/es6/#test-proper_tail_calls_(tail_call_optimisation)

This r/node reddit thread offers some insight and links to this v8 blog post 其中包括:

[...] the V8 team strongly support denoting proper tail calls by special syntax. There is a pending TC39 proposal called syntactic tail calls to specify this behavior, co-championed by committee members from Mozilla and Microsoft. [...] The V8 team plans to resolve the issue at the next TC39 meeting before shipping implicit proper tail calls or syntactic tail calls by default.

也就是说,V8 不想实现 as-spec 的 ES6 特性,而更喜欢 tail-call 的显式语法,例如 the ones proposed for TC39

另请参阅: