editar depuracion debugger debuggear debug consola chrome javascript callstack

javascript - depuracion - "RangeError: el tamaño máximo de pila de llamadas excedió" ¿Por qué?



depuracion de javascript (3)

Si corro

Array.apply(null, new Array(1000000)).map(Math.random);

en Chrome 33, me sale

RangeError: Maximum call stack size exceeded

¿Por qué?


Aquí falla en Array.apply(null, new Array(1000000)) y no en la llamada .map .

Todos los argumentos de las funciones deben caber en la pila de llamadas (al menos los punteros de cada argumento), por lo que en este caso hay demasiados argumentos para la pila de llamadas.

Necesitas entender qué es la pila de llamadas .

Stack es una estructura de datos LIFO, que es como una matriz que solo admite los métodos push y pop.

Déjame explicarte cómo funciona con un simple ejemplo:

function a(var1, var2) { var3 = 3; b(5, 6); c(var1, var2); } function b(var5, var6) { c(7, 8); } function c(var7, var8) { }

Cuando aquí se llama a la función a , llamará a b y c . Cuando se b y c , las variables locales de a no son accesibles allí debido a los roles de alcance de Javascript, pero el motor de Javascript debe recordar las variables locales y los argumentos, por lo que los insertará en la pila de llamadas. Digamos que está implementando un motor de JavaScript con el lenguaje Javascript como Narcissus .

Implementamos callStack como matriz:

var callStack = [];

Cada vez que una función llamada empujamos las variables locales en la pila:

callStack.push(currentLocalVaraibles);

Una vez que la llamada a la función finaliza (como en a , hemos llamado b , b ha terminado de ejecutarse y debemos volver a a ), recuperamos las variables locales al abrir la pila:

currentLocalVaraibles = callStack.pop();

Entonces, cuando a queramos llamar c nuevamente, presione las variables locales en la pila. Ahora, como saben, los compiladores para ser eficientes definen algunos límites. Aquí cuando estás haciendo Array.apply(null, new Array(1000000)) , tu objeto currentLocalVariables será enorme porque tendrá 1000000 variables dentro. Dado que .apply pasará cada elemento del conjunto dado como un argumento para la función. Una vez empujado a la pila de llamadas, esto excederá el límite de memoria de la pila de llamadas y arrojará ese error.

El mismo error ocurre en la recursión infinita ( function a() { a() } ) como demasiadas veces, las cosas se han enviado a la pila de llamadas.

Tenga en cuenta que no soy un ingeniero compilador y esto es solo una representación simplificada de lo que está sucediendo. Realmente es más complejo que esto. En general, lo que se empuja a la pila de llamadas se llama cuadro de pila que contiene los argumentos, las variables locales y la dirección de la función.


La respuesta con for es correcta, pero si realmente quieres usar el estilo funcional for evitar el enunciado, puedes usar lo siguiente en lugar de tu expresión:

Array.from (Array (1000000), () => Math.random ());

El método Array.from () crea una nueva instancia de Array a partir de un objeto similar a una matriz o iterable. El segundo argumento de este método es una función de mapa para invocar cada elemento de la matriz.

Siguiendo la misma idea, puede volver a escribir utilizando el operador ES2015 Spread :

[... Array (1000000)]. Map (() => Math.random ())

En ambos ejemplos, puede obtener un índice de la iteración si lo necesita, por ejemplo:

[... Array (1000000)]. Map ((_, i) => i + Math.random ())


Los navegadores no pueden manejar tantos argumentos. Vea este fragmento, por ejemplo:

alert.apply(window, new Array(1000000000));

Esto produce RangeError: Maximum call stack size exceeded que es el mismo que en su problema.

Para resolver eso, hazlo:

var arr = []; for(var i = 0; i < 1000000; i++){ arr.push(Math.random()); }