2013-04-18 28 views
10

v0.10.4nodejs setTimeout wyciek pamięci?

Oto prosta pętla, która skutkuje coraz większego zużycia pamięci:

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

redx(); 

Co robię źle ??

EDIT

OK, po prostu starał się sugestia, aby odwołać się do obiektu limitu czasu w zakresie i wydaje się, że zbieranie śmieci nie kopać po około 40 sekundach, oto skróconych dzienników od góry:

3941 korzeń 20 0 32944 7284 4084 S 4,587 3,406 0: 01,32 węzeł
3941 głównego 20 0 32944 7460 4084 S 2,948 3,489 0: 01,59 węzeł
3941 głównego 20 0 32944 7516 4084 S 2,948 3,515 0: 01,68 węzeł
3941 głównego 20 0 33968 8400 4112 S 2.948 3.928 0: 02.15 węzeł
3941 głównego 20 0 33968 8920 4112 S 3,275 4,171 0: 02,98 węzeł
3941 głównego 20 0 33968 8964 4112 S 2,948 4,192 0: 03,07 węzeł
3941 głównego 20 0 33968 9212 4112 S 2,953 4,308 0: 03.16 węzeł
3941 korzeń 20 0 33968 9212 4112 S 2,953 4,308 0: 03,25 węzeł
3941 głównego 20 0 33968 9212 4112 S 3,276 4,308 0: 03,35 węzeł
3941 głównego 20 0 33968 9212 4112 S 2,950 4,308 0: 03,44 węzeł

+0

Niewiarygodne, sam się nad tym zastanawiałem. Domyślam się, że Węzeł nie zbiera zamknięć anonimowej funkcji. – dualed

+0

Na jakim systemie operacyjnym pracujesz? – dualed

+0

Testuję to pod ARCH. – crankshaft

Odpowiedz

4

Nie pomysł dlaczego, ale najwyraźniej jeśli odwołujesz się do obiektu limitu czasu w zakresie funkcji nodejs zrobi to poprawnie.

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

redx(); 
+0

Dzięki, właśnie przetestowałem twój kod i niestety dla mnie to nie rozwiązuje problemu i nie widzę żadnej zauważalnej różnicy w zużyciu pamięci. – crankshaft

+0

Korekta, właśnie na to patrzyłem i zużycie pamięci ciągle wzrasta, a następnie osiąga szczyt po około 40 sekundach! – crankshaft

+0

Dziwne, wyraźnie widzę wzrost wykorzystania pamięci, a następnie powrót do wartości początkowej (domyślam się, że kiedy gc kopie) –

3

Właściwie, myślę, że to może być po prostu sposób, w jaki działa garbage collector V8.

W moim systemie, stertę węzła ma tendencję do wzrostu do 48 MB, a następnie stabilizacji, więc myślę, że jeśli utrzymasz swój program uruchomiony przez długi czas, zużycie pamięci ostatecznie ustabilizuje.

Możesz uzyskać informacje o tym, kiedy/jak kopie GC, uruchamiając węzeł za pomocą jednej z opcji wiersza poleceń V8: flaga --trace_gc.

Podczas pierwszych prób z Redis, systematycznie łączyłeś/rozłączałeś się z Redis przy każdym połączeniu. To generuje śmieci. Powinieneś raz otworzyć połączenie i używać go wielokrotnie. Niemniej jednak, nawet gdy to robię, zużycie pamięci zwykle się stabilizuje. Oto ewolucja zużycia pamięci w tym przykładzie z 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

tutaj, stabilizacja po 60 MB wydaje się być dość oczywista.

+0

Dzięki, tak originaly Myślałem, że to był problem z redis/memcache, ale po usunięciu kodu do absolutnego minimum, okazało się, że właśnie setTimeout spowodował ten wyciek. Powodem, dla którego ciągle otwierałem nowe połączenie, jest to, że może to trwać wiele miesięcy i nie byłem pewien, czy trzymanie otwartego połączenia localhost przez taki czas byłoby niezawodne. – crankshaft

+0

Mogę potwierdzić powyższy wykres. Wydaje się, że Nodejs stabilizuje zużycie pamięci po pewnym czasie. Jest to bardzo typowe w większości GC. Miałem nawet takie same wyniki, generując izolowany zakres, który wywoływał 'redx()' w pętli setTimeout. Miałem również ten sam wykres, wywołując 'setTimeout (redx.bind (null), 50);'. Zgaduję, że w powyższym przykładzie 'var client = ...' staje się nieosiągalny po następnych pętlach, więc po pewnym czasie zbiera śmieci i dlatego przeciek pamięci również nie powinien mieć zastosowania. może wygenerować przeciek Mem do Redis, ale to nie jest dyskusja. –