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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11193421/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 12:20:52  来源:igfitidea点击:

Stack vs. Heap in Javascript? (Maximum call stack size exceeded)

javascriptmemory-managementstackheap

提问by Markus A.

I'm trying to build a web-page for which I need to shovel around several 100MB of data in JavaScript. With different browsers I run into "maximum call stack size exceeded" errors at different data amounts.

我正在尝试构建一个网页,我需要在 JavaScript 中挖掘大约 100MB 的数据。使用不同的浏览器,我遇到了不同数据量的“超出最大调用堆栈大小”错误。

Can I fix this issue by going through my code and trying to move local variables inside functions into a more global scope to try to get them to be allocated on the heap instead of the stack? Or do these concepts not exist in JavaScript? (As far as I know, I don't have any major recursive loops in my data, so it really is a couple of huge strings / number arrays that seem to be causing the error)

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

If this isn't possible, are there ways to ask the browser to reserve more memory?

如果这是不可能的,有没有办法让浏览器保留更多内存?

采纳答案by Oleg V. Volkov

There's no separation of memory into stack/heap in Javascript. What you seeing could be one of following:

在 Javascript 中没有将内存分成堆栈/堆。您看到的可能是以下之一:

  1. Recursion that ran too deep. In that case you'll need to review your algorithm to make it more iterative and use less recursion so you don't hit call stacklimits imposed by browsers.
  2. If your algorithm do not have deep recursion, this might still be just a deep enough call, considering that your code is generated.
  3. Lastly, some engines may allocate function arguments and scoped named variables on some sort of internal stack for fast lookup. If you (or automatically generated code) happens to literally use thousands of local variables or arguments in function, this may overflow engine-specific limits as well.
  1. 运行太深的递归。在这种情况下,您需要检查您的算法以使其更具迭代性并使用更少的递归,这样您就不会达到浏览器强加的调用堆栈限制。
  2. 如果你的算法没有深度递归,考虑到你的代码是生成的,这可能仍然只是一个足够深的调用。
  3. 最后,一些引擎可能会在某种内部堆栈上分配函数参数和作用域命名变量以进行快速查找。如果您(或自动生成的代码)碰巧在函数中使用了数千个局部变量或参数,这也可能会溢出特定于引擎的限制。

回答by Markus A.

OK, figured out the problem. There really was no recursion in my code. It is indeed possible to call JavaScript functions with hundreds of arguments if they are "varargs" functions like for example <array>.splice(...), which was my offender.

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

Aside: GWTimplements the Java function System.arraycopy(...)using the JavaScript splice function in a more-or-less clever way.

旁白:GWTSystem.arraycopy(...)使用 JavaScript splice 函数以一种或多或少巧妙的方式实现了 Java 函数。

splice accepts an arbitrary number of input elements to insert into the target array. It is possible to pass these input elements from another array by using the following construct:

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

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

This is equivalent to calling:

这相当于调用:

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

If elementsgets big (see below for what "big" means for different browsers), you canget a "Maximum call stack size exceeded" error withoutrecursion as the contents of it will be loaded onto the stack for the function call.

如果元素变大(请参阅下文,了解“大”对于不同浏览器的含义),您可能会在没有递归的情况下收到“超出最大调用堆栈大小”错误因为它的内容将被加载到函数调用的堆栈中。

Here's a short script that demonstrates this issue:

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

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);
}

Using this script, "big" means the following:

使用此脚本,“大”的含义如下:

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

And the winner is: Internet Explorer 8 for a change! It can use up all system memory, before this function call fails.

赢家是:Internet Explorer 8 的改变!在此函数调用失败之前,它可以用完所有系统内存。

A side note: Firefox and Opera actually throw a different (more useful) error message: Function.prototype.apply: argArray is too large

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