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

匿名 (未验证) 提交于 2019-12-03 00:48:01

问题:

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.

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)

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

回答1:

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

  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 stack limits 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.


回答2:

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 .splice(...), which was my offender.

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

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:

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 elements gets big (see below for what "big" means for different browsers), you can get a "Maximum call stack size exceeded" error without recursion 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

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

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

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



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!