递归 - 测试最大堆栈大小时调用堆栈无法弹出

Recursion - Call stack fails to pop when testing the maximum stack size

基本上调用栈会开始pop函数last-in函数调用returns时一一调用。但是,每当我尝试创建一个接近其最大大小的调用堆栈时,就会出现 uncaught expression

//Code for testing the stack size
var cnt = 0;

function test(){
 //Max stack size is nearer to ~41800
 if(cnt++ == 41763){
  console.log('finished');
  return true;
 }
 return test();
}

test();

所以上面的代码在 chromium 版本 49.0.2623.112 m 中为我抛出异常,如下所示,

Uncaught exception

< true

请注意上面的错误没有任何信息。我的问题是,

堆栈中的最后一个函数调用已返回 true,这意味着未超出堆栈大小。为什么没有返回该堆栈中的其他函数调用?出现此空白异常消息的原因是什么?

这里的问题是

console.log('finished');

这会向调用堆栈添加一些额外函数,使限制超出限制,但通过异常处理,您的代码无论如何都会被执行。

尝试在没有 console.log 的情况下 运行 它,你会看到你达到了极限,并看到了 true 或 exception。

console.log 不在 javascript 的规范中,因此行为未定义,可以在不同版本之间更改。所以在您的版本中发生的事情可能不会在我们的版本中发生。

这是对发生的事情最可能的解释:可以肯定 console.log 会增加堆栈的大小,并且因为是您在 return 之前调用的最后一条语句,它可以产生a Maximum call stack 有时是因为你已经非常接近极限了。 Maximum 调用可能发生在 console.log 代码内部(谁调用了其他东西),以及这个错误将如何处理它,这取决于 console.log 的代码。似乎 console.log 中的代码在发生错误时抛出未捕获的异常。现在,当您使用 try 捕获错误时,代码会继续,这就是出现 true 的原因。

下面是 jsfiddle 中的一个示例,我覆盖了 console.log,结果出现在 HTML 中。您可以通过删除 console.log 的覆盖代码来玩,看看情况如何变化。试试这个,如果结果看起来又很奇怪,请告诉我们。

值得注意的是,当出现Maximum call stack size exceeded错误时,它也取决于堆栈帧的大小(局部变量)。

注意:在 ECMAScript 6 spec 中,如果函数调用是函数中的最后一个动作,它不会进入堆栈,但会 运行 "immediately",所以您的代码将 运行 所有数字都没有错误,无论您输入什么数字。