浏览器Javascript栈大小限制

90

我在客户端Javascript中遇到了一些堆栈溢出问题,尤其是在IE浏览器中发生了这种情况。这是在一个第三方库内部发生的,该库进行了一些函数调用,由于IE浏览器的堆栈限制较低,所以它们偶尔会出现故障。

然后我编写了一个小测试HTML来测试某些浏览器的堆栈大小限制,并发现与运行Windows 7操作系统、8GB RAM的笔记本电脑上运行的FF 7或Chrome 14相比,IE8实际上具有较小的堆栈限制:

<html>
<body>

<!-- begin Script: -->
<script type="text/javascript">

function doSomething(){

  var i = 3200;
  doSomethingElse(i);

}

function doSomethingElse(i){
  if (i == 0) return -1;
  doSomethingElse(i-1);
}

doSomething(); 

</script>
<!-- END OF PAGE -->

</body>
</html>

当值在3200左右时,IE会引发堆栈溢出错误,相较于IE,Firefox和Chrome可以处理更深层次的递归。

我想知道是否有一种方法可以在运行时将堆栈溢出异常与引发它的Javascript函数绑定,在IE或任何其他浏览器中,并且是否可以在错误引发时提供包含堆栈中函数链的堆栈跟踪。


2
3200次调用足够的堆栈空间了。Python程序员(那些不倾向于编写递归下降解析器或者只是为了好玩而用递归替换完全简单的循环的人)在1000次调用限制下也能很好地工作。你在干什么? - user395760
4
虽然这段话没有严格使用疑问语气,但最后一句话“我想知道是否有......”可以改为“是否有......?”并以问号结尾,这样就能构成一个比较直接的问题。 - jball
感谢您的反馈,我会更好地澄清问题。 - guilhebl
那些不想编写递归下降解析器的人,还有其他类型的解析器吗? - Avin Kavish
2个回答

164

使用简单的测试:

var i = 0;
function inc() {
  i++;
  inc();
}
    
try {
  inc();
}
catch(e) {
  // The StackOverflow sandbox adds one frame that is not being counted by this code
  // Incrementing once manually
  i++;
  console.log('Maximum stack size is', i, 'in your current browser');
}

Internet Explorer

  • IE6: 1130
  • IE7: 2553
  • IE8: 1475
  • IE9: 20678
  • IE10: 20677

Mozilla Firefox

  • 3.6: 3000
  • 4.0: 9015
  • 5.0: 9015
  • 6.0: 9015
  • 7.0: 65533
  • 8b3: 63485
  • 17: 50762
  • 18: 52596
  • 19: 52458
  • 42: 281810
  • 89: 10746
  • 91: 26441

Google Chrome

  • 14: 26177
  • 15: 26168
  • 16: 26166
  • 25: 25090
  • 47: 20878
  • 51: 41753
  • 93: 13903

Safari

  • 4: 52426
  • 5: 65534
  • 9: 63444
  • 14: 45606

Safari iOS

  • 15: 7909

Opera

  • 10.10: 9999
  • 10.62: 32631
  • 11: 32631
  • 12: 32631
  • 78: 13908

Edge

  • 87: 13970
  • 93: 13903

Yandex

  • 21: 13909

针对您的问题,请使用浏览器的开发者工具查看堆栈。在IE 8+中,按下F12,进入“脚本”选项卡,然后单击“开始调试”。当抛出异常时它会停止,并且您可以查看调用栈。您还可以使用Chrome的开发者工具,按Ctrl+Shift+J


9
你可以在Chrome中也使用F12。 - Ruan Mendes
1
使用测试 http://jsfiddle.net/9YMDF/show/,我在Chrome 28上得到了大约21000的结果,在Firefox 20+上得到了26000..53000的结果,在Windows 7 SP1 64位的IE10上得到了大约3000的结果。 Opera 12.X的堆栈深度接近32768。而我发现一台不幸的IE8安装其堆栈深度等于276! - Victor
你可以将这些结果与此处链接的BrowserScope进行比较。 - Janus Troelsen
10
我认为这些数字与浏览器无关,而是与应用程序当前保留的内存相关。因此,答案变化很大。例如,我刚刚运行了该测试,在带有许多扩展的 Chrome 56 中获得了20922的分数,在相当简单的 Firefox 49 中获得了8921的分数。而在完全未修改的 Edge 浏览器中,我得到了16615的分数。 - roberto tomás
Node.js在macOS(v8.4.0)和Debian Linux(v8.6.0)上的得分约为7800。 - Kaivosukeltaja
显示剩余2条评论

8

这是与浏览器相关的问题,不仅涉及堆栈大小,还包括优化、尾递归优化等。我想唯一可靠的方法就是编写不会在堆栈中放置大量内容的代码,或者手动测试(深入阅读文档)每个浏览器。毕竟,当您看到“too much recursion”或类似错误时,您已经知道您的代码出了严重的问题。


尾调用优化(TCO)在JavaScript中真的实现了吗?我读到ES6可能会得到支持,但我不认为它已经被实现了。 - Janus Troelsen
目前TCO在Chrome中是一个标志(正在评估两种不同的实现方式)。我不知道有哪些浏览器默认实现了它。 - Jethro Larson
1
@JanusTroelsen:ES2015(“ES6”)确实要求引擎执行TCO。V8已经具备了这个功能,但V8团队认为它还不稳定,因此您需要启用它。(V8将它们开始的功能分类为“发布”[完成],“稳定”和“正在进行中”。TCO仍然处于“正在进行中”的状态,但是V8的三个代码生成器都具备基本功能。我认为他们还没有将其提升为“稳定”,因为他们仍在优化/查找错误/修复错误。更多信息请参见:https://dev59.com/umAg5IYBdhLWcg3wu87o#30369729) - T.J. Crowder
目前Safari是唯一具有正确尾调用优化(TCO)的浏览器。 - ridderhoff
将大量元素放入堆栈的一个使用案例是 array1.push(...array2),这比 array1 = array1.concat(array2) 快得多,但当 array2 太长时会抛出 'max stack size exceeded' 错误。参见此处 - milahu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接