2013-04-18 11 views
10

v0.10.4nodejs setTimeout Speicherleck?

Hier ist die einfache Schleife, die in einer ständig wachsenden Speichernutzung führt:

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

redx(); 

Was mache ich falsch ??

EDIT

OK, hätte gerade versucht, den Vorschlag, das Timeout-Objekt in dem Umfang zu verweisen und es scheint, dass die Garbage Collection nach etwa 40 Sekunden tritt in sich, hier abgekürzt Protokolle von TOP:

3941 Wurzel 20 0 32944 7284 4084 S 4.587 3.406 0: 01.32 Knoten
3941 Wurzel 20 0 32944 7460 4084 S 2.948 3.489 0: 01.59 Knoten
3941 Wurzel 20 0 32944 7516 4084 S 2.948 3.515 0: 01,68 Knoten
3941 Wurzel 20 0 33968 8400 4112 S 2,948 3,928 0: 02,15 Knoten
3941 Wurzel 20 0 33968 8920 4112 S 3.275 4.171 0: 02.98 Knoten
3941 Wurzel 20 0 33968 8964 4112 S 2.948 4.192 0: 03.07 Knoten
3941 Wurzel 20 0 33968 9212 4112 S 2.953 4.308 0: 03.16 Knoten
3941 Wurzel 20 0 33968 9212 4112 S 2.953 4.308 0: 03.25 Knoten
3941 Wurzel 20 0 33968 9212 4112 S 3.276 4.308 0: 03,35 Knoten
3941 Wurzel 20 0 33968 9212 4112 S 2.950 4.308 0: 03,44 Knoten

+0

Unglaublich, ich hatte mich gestern selbst gefragt. Meine Vermutung ist, dass Node die Schließungen der anonymen Funktion nicht sammelt. – dualed

+0

An welchem ​​Betriebssystem arbeiten Sie? – dualed

+0

Ich teste das unter ARCH. – crankshaft

Antwort

4

No Idee, warum aber scheinbar, wenn Sie das Timeout-Objekt im Rahmen der Funktion Nodejs Verweis wird der Müll richtig sammeln.

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

redx(); 
+0

Danke, ich habe gerade Ihren Code getestet und leider löst er das Problem nicht und ich sehe keinen merklichen Unterschied im Speicherverbrauch. – crankshaft

+0

Korrektur, ich habe mir das gerade nochmal angeschaut und der Speicherverbrauch steigt anfangs immer weiter und erreicht dann nach etwa 40 Sekunden den Maximalwert! – crankshaft

+0

komisch, ich kann klar sehen, Speicherverbrauch erhöhen und dann zurück zum Anfangswert (ich denke, das ist, wenn GC tritt) –

3

Eigentlich denke ich, es könnte nur die Art, wie der V8-Müllsammler funktioniert.

Auf meinem System, Knoten Heap neigt dazu, bis zu 48 MB zu erhöhen und dann zu stabilisieren, also denke ich, wenn Sie Ihr Programm für eine lange Zeit laufen, wird der Speicherverbrauch schließlich stabilisieren.

Sie können Informationen darüber erhalten, wann und wie der GC startet, indem Sie den Knoten mit einer der V8-Befehlszeilenoptionen starten: das Flag --trace_gc.

Bei Ihren ersten Versuchen mit Redis haben Sie bei jedem Anruf systematisch Verbindungen zu Redis hergestellt. Dies neigt dazu, Müll zu erzeugen. Sie sollten einmal eine Verbindung öffnen und sie mehrmals verwenden. Trotzdem neigt der Speicherverbrauch dazu, sich zu stabilisieren, selbst wenn ich dies tue. Hier ist die Entwicklung der Speicherverbrauch auf diesem Beispiel mit 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

Hier scheint die Stabilisierung nach 60 MB ziemlich offensichtlich zu sein.

+0

Danke, ja ursprünglich dachte ich, das war ein Problem mit redis/memcache, aber nachdem ich den Code auf ein Minimum reduziert hatte, stellte ich fest, dass nur das setTimeout zu diesem Leck führte. Der Grund, warum ich eine neue Verbindung geöffnet habe, ist, dass dies für viele Monate laufen könnte und ich unsicher war, ob das Offenhalten einer Localhost-Verbindung für diese Zeitspanne zuverlässig wäre. – crankshaft

+0

Ich kann die obige Grafik bestätigen. Nodejs scheint seinen Speicherverbrauch nach einiger Zeit zu stabilisieren. Dies ist in den meisten GCs sehr typisch. Ich hatte sogar die gleichen Ergebnisse, indem ich einen isolierten Bereich erzeugte, der 'redx()' in einer setTimeout-Schleife aufruft. Ich hatte auch die gleiche Grafik, indem ich 'setTimeout (redx.bind (null), 50);'. Ich habe eine Vermutung im obigen Beispiel, 'var client = ...' wird nach den nächsten Loops unerreichbar, so dass Garbage nach einiger Zeit gesammelt wird und Speicherlecks nicht gelten sollten. Es könnte Mem Leak zu Redis generieren, aber das ist aus Diskussion. –