2015-10-22 21 views
7

mio MCVE è il seguenteLoop di console.log in nodejs

var i = 0; 
for(;;) 
    console.log(i++) 

Quando faccio questo, ad un certo momento, il mio nodejs si ferma solo roba stampa, dandomi un output simile a questo

[...] 
684665 
684666 
684667 

E poi, ho ottenuto questo:

<--- Last few GCs ---> 

    69097 ms: Scavenge 1397.2 (1456.7) -> 1397.2 (1456.7) MB, 0.8/0 ms (+ 1.7 ms in 1 steps since last GC) [allocation failure] [incremental marking delaying mark-sweep]. 
    70462 ms: Mark-sweep 1397.2 (1456.7) -> 1396.0 (1456.7) MB, 1364.9/0 ms (+ 2.8 ms in 2 steps since start of marking, biggest step 1.7 ms) [last resort gc]. 
    71833 ms: Mark-sweep 1396.0 (1456.7) -> 1397.1 (1456.7) MB, 1370.2/0 ms [last resort gc]. 


<--- JS stacktrace ---> 

==== JS stack trace ========================================= 

Security context: 0xcdf79d37399 <JS Object> 
    1: formatPrimitive(aka formatPrimitive) [util.js:~411] [pc=0x634d9f4113f] (this=0xcdf79d04131 <undefined>,ctx=0x17b18f4d561 <an Object with map 0x32fd25043ef9>,value=16248021) 
    2: formatValue(aka formatValue) [util.js:223] [pc=0x634d9f1fdbb] (this=0xcdf79d04131 <undefined>,ctx=0x17b18f4d561 <an Object with map 0x32fd25043ef9>,value=16248021,recurseTimes=2) 
    3: inspect(aka inspect) [uti... 

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory 
[1] 19446 abort (core dumped) node 

mi chiedevo, cosa si può fare che console.log potrebbe causare un errore di memoria insufficiente?

+0

Penso che stia traboccando un buffer e deve essere svuotato – Hristo

+0

@Chris Ho modificato il mio post, non era un problema di svuotamento – tforgione

+0

Potrebbe valere la pena aprire un biglietto sul [repository NodeJS] (https://github.com/ nodejs/node/issues) link a questa domanda. –

risposta

2

Dopo l'apertura di un problema sul repository nodejs, ho ottenuto il following answer: comportamento

E 'previsto: console.log è asincrono, la memoria associata a ogni chiamata non può essere recuperata fino al prossimo tick del loop eventi. Nel tuo esempio, la spunta successiva non avviene mai a causa del ciclo infinito.Se si riscrive il vostro esempio a un approccio callback-driven, che continua a funzionare per sempre:

let i = 0; 
const next =() => process.stdout.write(`${i++}\n`, next); 
next(); 
5

Secondo questa discussione: https://groups.google.com/forum/#!topic/nodejs/KtONbpVV68U

Ogni volta che si chiama console.log (o un altro metodo di registrazione), l'oggetto console allocherà po 'di memoria. Questa memoria sarà libera dal garbage collector al suo prossimo tick. Ma se hai un loop troppo grande, il tick successivo non arriva mai.

Ma i provato questo:

setInterval(function() { 
    for (var i = 0; i < 100000; ++i) { 
     console.log(i); 
    } 
}, 10000) 

Secondo la discussione gruppo google, tra ogni intervallo, NodeJS garbage collector dovrebbe liberare la memoria allocata dal console.log. Ma non è. Ogni volta che il ciclo è in esecuzione, il mio processo richiede più RAM.

Ho anche testato questo:

var fs = require('fs') 
var output = fs.createWriteStream('./stdout.log'); 
var errorOutput = fs.createWriteStream('./stderr.log'); 
var logger = new console.Console(output, errorOutput); 

var i = 0; 
for (;;) { 
    logger.log(i++); 
} 

il comportamento è lo stesso. Il processo richiede sempre più RAM finché non si blocca (perché è disponibile più RAM). E il file stdout.log è sempre vuoto.

Infine, ho provato questo:

var fs = require('fs') 
var output = fs.createWriteStream('./stdout.log'); 
var errorOutput = fs.createWriteStream('./stderr.log'); 
var logger = new console.Console(output, errorOutput); 

setInterval(function() { 
    for (var i = 0; i < 100000; i++) { 
     logger.log(i); 
    } 
}, 5000) 

questo esempio è interessante. Perché tra ogni intervallo, viene scritto stdout.log (le righe vengono aggiunte al file) e la RAM recuperata dal processo non aumenta. Tra ogni intervallo il garbage collector fa il suo lavoro.

Penso che l'oggetto console non gestisca bene il buffer. Ma è ancora strano. Se si utilizza l'output standard (con solo console.log), è come se l'oggetto della console fosse conservato nella memoria fino a quel momento stampato. E non è mai pulito. E se usi un'uscita di file, tutto funziona perfettamente (eccetto se lo scrivi in ​​un ciclo infinito, ovviamente).

forse è perché la versione NodeJS, sto lavorando con un NodeJS 0.12.7

+0

Il tuo primo ' l'esempio di setInterval' non sembra sovraccaricare la mia RAM, forse a causa della mia versione (4.2.1). – tforgione

+0

Come uscire dal ciclo foor? Ho più codice da eseguire, ma non arriva mai da quando setInterval continua a sparare. –

1

Vedi i dettagli in discussione al https://github.com/nodejs/node/issues/11568

Inoltre, nel modo descritto nella documentazione console è sincrona quando stdout reindirizzato a un file. Ma il comportamento descritto è stato riprodotto anche in questo caso.

Un loop infinito con l'output console.log() reindirizzato a un file non si blocca Nodo v4.x ma si blocca il nodo v6. Questo sembra un bug introdotto in v6.

Come soluzione temporanea è possibile utilizzare la patch console-sync.