在Javascript中堆栈与堆? (超出最大调用堆栈大小)

时间:2012-06-25 16:35:22

标签: javascript memory-management stack heap

我正在尝试构建一个网页,我需要在JavaScript中搜索几个100MB的数据。对于不同的浏览器,我在不同的数据量下遇到“超出最大调用堆栈大小”错误。

我是否可以通过查看代码并尝试将函数内的局部变量移动到更全局的范围来尝试将它们分配到堆而不是堆栈来解决此问题?或者JavaScript中不存在这些概念? (据我所知,我的数据中没有任何主要的递归循环,所以它确实是一些巨大的字符串/数字数组似乎导致错误)

如果无法做到这一点,有没有办法让浏览器保留更多内存?

2 个答案:

答案 0 :(得分:27)

好的,找出问题所在。我的代码中确实没有递归。如果它们是“varargs”函数,例如<array>.splice(...),这是我的罪犯,确实可以调用带有数百个参数的JavaScript函数。

除此之外:GWT以一种或多或少的聪明方式使用JavaScript拼接功能实现Java函数System.arraycopy(...)

splice接受任意数量的输入元素以插入目标数组。可以使用以下构造从另一个数组传递这些输入元素:

var arguments = [index, howmany].concat(elements);
Arrays.prototype.splice.apply(targetarray, arguments);

这相当于调用:

targetarray.splice(index, howmany, elements[0], elements[1], elements[2], ...);

如果元素变大(请参阅下面的“大”对不同浏览器的意义),可以获得“超出最大调用堆栈大小”错误没有递归,因为它的内容将被加载到函数调用的堆栈中。

这是一个演示此问题的简短脚本:

var elements = new Array();
for (i=0; i<126000; i++) elements[i] = 1;
try {
    var arguments = [0, 0].concat(elements);
    Array.prototype.splice.apply(elements, arguments);
    alert("OK");
} catch (err) {
    alert(err.message);
}

使用此脚本,“big”表示以下内容:

  • Chrome 19:元素包含~125,000个数字
  • Safari 5.1(在Windows上):元素包含~65,000个数字
  • Firefox 12:元素包含~500,000个数字
  • Opera 11.61:元素包含~1,000,000个数字

获胜者是:Internet Explorer 8进行更改!在此函数调用失败之前,它可以用尽所有系统内存。

旁注:Firefox和Opera实际上抛出了一个不同的(更有用的)错误消息:Function.prototype.apply:argArray太大

答案 1 :(得分:16)

Javascript中没有内存分离到堆栈/堆中。你看到的可能是以下之一:

  1. 过长的递归。在这种情况下,您需要检查您的算法以使其更加迭代并使用更少的递归,这样您就不会达到浏览器强加的调用堆栈限制。
  2. 如果您的算法没有深度递归,考虑到您的代码已生成,这可能仍然只是一个足够深的调用。
  3. 最后,一些引擎可能会在某种内部堆栈上分配函数参数和作用域命名变量,以便快速查找。如果您(或自动生成的代码)恰好在函数中使用了数千个局部变量或参数,那么这可能会超出特定于引擎的限制。