2013-04-18 19 views
10

v0.10.4nodejs setTimeout perdita di memoria?

Ecco il semplice ciclo che si traduce in un utilizzo della memoria sempre crescente:

function redx(){ 
     setTimeout(function(){ redx() },1000); 
     console.log('loop'); 
} 

redx(); 

Cosa faccio di sbagliato ??

EDIT

OK, appena provato il suggerimento per fare riferimento all'oggetto timeout nel campo di applicazione e sembra che la raccolta dei rifiuti non calci in dopo circa 40 secondi, i registri Ecco abbreviati da TOP:

3941 radice 20 0 32944 7284 4084 S 4.587 3.406 0: 01.32 nodo
3941 radice 20 0 32944 7460 4084 S 2.948 3.489 0: 01.59 nodo
3941 radice 20 0 32944 7516 4084 S 2.948 3.515 0: 01,68 nodo
3941 radice 20 0 33968 8400 4112 S 2.948 3.928 0: 02.15 nodo
3941 radice 20 0 33968 8920 4112 S 3.275 4.171 0: 02,98 nodo
3941 radice 20 0 33968 8964 4112 S 2.948 4.192 0: 03.07 nodo
3941 radice 20 0 33968 9212 4112 S 2.953 4.308 0: 03.16 nodo
3941 radice 20 0 33968 9212 4112 S 2.953 4.308 0: 03.25 nodo
3941 radice 20 0 33968 9212 4112 S 3.276 4.308 0: 03,35 nodo
3941 radice 20 0 33968 9212 4112 S 2.950 4.308 0: 03,44 nodo

+0

Incredibile, me lo stavo chiedendo ieri. La mia ipotesi è che il nodo non raccolga le chiusure della funzione anonima. – dualed

+0

Quale sistema operativo stai lavorando? – dualed

+0

Lo sto testando sotto ARCH. – crankshaft

risposta

4

n idea perché, ma a quanto pare se fai riferimento all'oggetto timeout nell'ambito della funzione nodejs eseguirà il garbage collector in modo corretto.

function redx(){ 
     var t = setTimeout(function(){ redx() },50); 
     console.log('hi'); 
} 

redx(); 
+0

Grazie, ho appena testato il tuo codice e sfortunatamente per me non risolve il problema e non vedo differenze evidenti nel consumo di memoria. Correzione – crankshaft

+0

, l'ho appena guardato e l'utilizzo della memoria continua ad aumentare inizialmente e poi si alza dopo circa 40 secondi! – crankshaft

+0

strano, posso chiaramente vedere aumentare l'utilizzo della memoria e poi tornare al valore iniziale (credo che quando gc calcia) –

3

In realtà, penso che potrebbe essere proprio il modo in cui il garbage collector V8 funziona.

Sul mio sistema, l'heap del nodo tende ad aumentare fino a 48 MB e quindi si stabilizza, quindi penso che se si mantiene il programma in esecuzione per un lungo periodo, il consumo di memoria si stabilizzerà alla fine.

È possibile avere informazioni su quando/come viene avviato il GC avviando il nodo con una delle opzioni della riga di comando V8: il flag --trace_gc.

Nei primi tentativi con Redis, si stava collegando/disconnettendo sistematicamente da Redis ad ogni chiamata. Questo tende a generare spazzatura. Dovresti aprire una connessione una volta e usarla molte volte. Tuttavia, anche quando lo faccio, il consumo di memoria tende a stabilizzarsi. Qui è l'evoluzione del consumo di memoria in questo esempio con Redis:

// something close to your initial function (when Redis was still in the picture) 
function redx(){ 
    var client = redis.createClient(); 
    client.get("tally", function(err, reply) { 
     client.quit(); 
    }); 
    setTimeout(function(){ redx() }, 50); 
} 

Evolution of memory consumption with Redis connect/disconnect

Qui, la stabilizzazione dopo 60 MB sembra essere abbastanza ovvio.

+0

Grazie, sì originale ho pensato che questo fosse un problema con redis/memcache ma dopo aver rimosso il codice al minimo, ho scoperto che solo il setTimeout stava causando questa perdita. Il motivo per cui ho continuato ad aprire una nuova connessione, è che potrebbe essere eseguito per molti mesi e non ero sicuro che tenere aperta una connessione localhost per quel tempo sarebbe stata affidabile. – crankshaft

+0

Posso confermare il grafico sopra. Nodejs sembra stabilizzare il suo consumo di memoria dopo un po '. Questo è molto tipico nella maggior parte dei GC. Ho persino avuto gli stessi risultati generando un ambito isolato che stava chiamando 'redx()' in un ciclo setTimeout. Ho anche avuto lo stesso grafico chiamando 'setTimeout (redx.bind (null), 50);'. Ho una supposizione nell'esempio sopra, 'var client = ...' sta diventando irraggiungibile dopo i cicli successivi, quindi recupera Garbage dopo un po ', quindi non dovrebbe essere applicata la perdita di memoria. potrebbe generare Mem Leak to Redis ma questo è fuori discussione. –