update tutorial node instalar español documentacion node.js stack-overflow callstack

node.js - tutorial - npm



Node.js: se ha excedido el tamaño máximo de la pila de llamadas (6)

Cuando ejecuto mi código, Node.js lanza la excepción "RangeError: Maximum call stack size exceeded" causado por demasiadas llamadas de recursión. Traté de aumentar Node.js stack-size por el sudo node --stack-size=16000 app , pero Node.js se bloquea sin ningún mensaje de error. Cuando ejecuto esto de nuevo sin sudo, entonces Node.js imprime ''Segmentation fault: 11'' . ¿Existe la posibilidad de resolver esto sin eliminar la llamada de recursión?

Gracias


Compruebe que la función que está importando y la que ha declarado en el mismo archivo no tienen el mismo nombre.

Te daré un ejemplo de este error. En JS expreso (usando ES6), considere la siguiente situación:

import {getAllCall} from ''../../services/calls''; let getAllCall = () => { return getAllCall().then(res => { //do something here }) } module.exports = { getAllCall }

El escenario anterior causará RangeError infame : el error de tamaño máximo de la pila de llamadas se ha excedido porque la función sigue llamándose tantas veces que se queda sin la cantidad máxima de llamadas.

La mayoría de las veces el error está en el código (como el anterior). Otra forma de resolver es aumentar manualmente la pila de llamadas. Bueno, esto funciona para ciertos casos extremos, pero no es recomendable.

Espero que mi respuesta te haya ayudado.


Debe ajustar su llamada de función recursiva a un

  • setTimeout ,
  • setImmediate o
  • process.nextTick

función para darle a node.js la oportunidad de borrar la pila. Si no haces eso y hay muchos bucles sin una función asíncrona real o si no esperas la devolución de llamada, tu RangeError: Maximum call stack size exceeded será inevitable .

Hay muchos artículos sobre "Potential Async Loop". Aquí hay uno .

Ahora un código de ejemplo más:

// ANTI-PATTERN // THIS WILL CRASH var condition = false, // potential means "maybe never" max = 1000000; function potAsyncLoop( i, resume ) { if( i < max ) { if( condition ) { someAsyncFunc( function( err, result ) { potAsyncLoop( i+1, callback ); }); } else { // this will crash after some rounds with // "stack exceed", because control is never given back // to the browser // -> no GC and browser "dead" ... "VERY BAD" potAsyncLoop( i+1, resume ); } } else { resume(); } } potAsyncLoop( 0, function() { // code after the loop ... });

Esto es correcto:

var condition = false, // potential means "maybe never" max = 1000000; function potAsyncLoop( i, resume ) { if( i < max ) { if( condition ) { someAsyncFunc( function( err, result ) { potAsyncLoop( i+1, callback ); }); } else { // Now the browser gets the chance to clear the stack // after every round by getting the control back. // Afterwards the loop continues setTimeout( function() { potAsyncLoop( i+1, resume ); }, 0 ); } } else { resume(); } } potAsyncLoop( 0, function() { // code after the loop ... });

Ahora su ciclo puede volverse demasiado lento, porque perdemos un poco de tiempo (un viaje de ida y vuelta del navegador) por ronda. Pero no tienes que llamar a setTimeout en cada ronda. Normalmente está bien hacerlo cada 1000 vez. Pero esto puede diferir dependiendo del tamaño de tu pila:

var condition = false, // potential means "maybe never" max = 1000000; function potAsyncLoop( i, resume ) { if( i < max ) { if( condition ) { someAsyncFunc( function( err, result ) { potAsyncLoop( i+1, callback ); }); } else { if( i % 1000 === 0 ) { setTimeout( function() { potAsyncLoop( i+1, resume ); }, 0 ); } else { potAsyncLoop( i+1, resume ); } } } else { resume(); } } potAsyncLoop( 0, function() { // code after the loop ... });


En algunos idiomas, esto se puede resolver con la optimización de la cola de llamadas, donde la llamada de recursión se transforma debajo de la campana en un bucle, por lo que no existe un error de tamaño de pila máximo alcanzado.

Pero en JavaScript los motores actuales no son compatibles con esto, está previsto para la nueva versión del lenguaje Ecmascript 6 .

Node.js tiene algunos indicadores para habilitar las características de ES6, pero aún no está disponible.

De modo que puede refactorizar su código para implementar una técnica llamada trampolining o refactor para transformar la recursividad en un bucle .


En cuanto al aumento del tamaño máximo de la pila, en las máquinas de 32 bits y 64 bits los valores predeterminados de asignación de memoria de V8 son, respectivamente, 700 MB y 1400 MB. En las versiones más nuevas de V8, V8 ya no establece límites de memoria en los sistemas de 64 bits, lo que teóricamente indica que no hay límite. Sin embargo, el SO (sistema operativo) en el que se está ejecutando el nodo siempre puede limitar la cantidad de memoria que V8 puede tomar, por lo que el límite verdadero de cualquier proceso dado no se puede establecer en general.

Aunque V8 pone a disposición la opción --max_old_space_size , que permite controlar la cantidad de memoria disponible para un proceso , aceptando un valor en MB. Si necesita aumentar la asignación de memoria, simplemente pase esta opción al valor deseado al generar un proceso de Nodo.

A menudo es una estrategia excelente para reducir la asignación de memoria disponible para una instancia de Nodo determinada, especialmente cuando se ejecutan muchas instancias. Al igual que con los límites de la pila, considere si las necesidades de memoria masiva se delegan mejor en una capa de almacenamiento dedicada, como una base de datos en memoria o similar.


Encontré una solución sucia:

/bin/bash -c "ulimit -s 65500; exec /usr/local/bin/node --stack-size=65500 /path/to/app.js"

Simplemente aumenta el límite de la pila de llamadas. Creo que esto no es adecuado para el código de producción, pero lo necesitaba para el script que se ejecuta solo una vez.


Si no desea implementar su propio contenedor, puede usar un sistema de cola, por ejemplo, async.queue , queue .