2014-11-26 8 views
5

Właśnie skończyłem rozwijać moją pierwszą aplikację node.js i teraz testuję ją na moim VPS. obserwując wykorzystanie zasobów procesu "węzeł", zauważyłem wzrost wykorzystania pamięci po zażądaniu strony (szczególnie niektórych). W szczególności, jeśli żądana strona jest stroną statyczną, wzrost jest minimalny. Jeśli żądana strona to/admin, wzrost może wynieść 1mb! Oczywiście, gdy żądany jest/admin, mój serwer robi więcej rzeczy niż obsługuje stronę statyczną. Łączy się z mongodb, wykonuje 4 "find", wiąże wyniki z szablonem html przy użyciu bind. Jaki jest problem? Ta pamięć używana, nigdy nie zostanie wydana !!! Pomyślałem więc, że w moim kodzie wystąpił błąd logiczny, ale potem zrobiłem kolejny test o wiele bardziej interesujący.Używana pamięć nigdy nie została zwolniona w węźle js. Bardzo dziwne

Rozważmy to bardzo prosty serwer nodejs:

var http = require('http'); 
http.createServer(function (req, res) { 
    res.writeHead(200, {'Content-Type': 'text/plain'}); 
    res.end('Hello World\n'); 
}).listen(3000, 'my_public_ip'); 

jeśli staram się wiele żądań z przeglądarki (po prostu przytrzymując klawisz F5 na minutę), wykorzystanie pamięci rośnie powoli i ilości pamięci używanej przez proces będzie nigdy zostać zwolniony, nawet po długim czasie i po zamknięciu przeglądarki. Teraz jest prawdopodobne, że w moim/administracyjnym kodzie jest jakiś błąd (1mb pamięci używanej i nigdy nie wydany dla każdego żądania jest bardzo wysoki!), Ale myślę, że to bardzo dziwne, że pamięć używana przez prosty skrypt powyżej nigdy nie zostanie wydana ! Co o tym myślisz? Jest sposób na uniknięcie tego?

także (w moim prawdziwym serwerze), użyłem memwatch w THYS sposób:

var memwatch = require('memwatch'); 
    memwatch.on('leak', function(info) { 
     console.log(info); 
     process.exit(1); 
    }); 

Gdybym wykonać wiele żądań z przeglądarki, po około 10 sekundach, że robię to, proces wyjdzie i jest to błąd:

{ start: Wed Nov 26 2014 08:21:07 GMT-0500 (EST), 
    end: Wed Nov 26 2014 08:22:04 GMT-0500 (EST), 
    growth: 4775624, 
    reason: 'heap growth over 5 consecutive GCs (57s) - 287.65 mb/hr' } 

Co to znaczy? Wygląda na to, że jest powiązany z śmieciarzem! Wiem, że lepiej byłoby wkleić tutaj mój/admin kod, ale fragment jest bardzo długi i jest powiązany ze zmiennymi globalnymi, więc nie da się go zrozumieć bez kopii 200 wierszy: D. Jeśli potrzebujesz więcej informacji, dam ci!

+1

Czy próbujesz ręcznie wymusić usuwanie pamięci? Sprawdź http://devjar.me/post/22886448979/manually-run-gc-in-node-js: "Uruchom węzeł z flagami -nouse_idle_notification i -expose_gc, a następnie, gdy chcesz uruchomić GC, po prostu zadzwoń globalnie .gc(). " – Joel

+0

Możesz zamieścić swój kod w gist/pastebin. Ale prosty fakt, że wspomniałeś o globalnych zmiennych, powinien wywołać alarm :) Potrzebujemy więcej informacji. Spróbuj też użyć 'memwatch' hot code, a nie zaraz po uruchomieniu. – randunel

+0

Ja (Andras) wypróbowałem powyższy kod z wymuszonym gc i jest bardzo bardzo stopniowy, ale coś się dzieje. Ponad 200 sekund i 580 000 wywołań używanych zużyło 40KB (maleńki bit), ale heapTotal wzrósł o 12MB, najpierw +4, a następnie +8. Prowadzę teraz 5-minutowy bieg – Andras

Odpowiedz

5

Nic dziwnego, że węzeł nie zwalnia pamięci, większość programów tego nie robi. Są chciwi: jeśli im się nie uda, dostaną więcej pamięci od systemu. Jeśli mają dodatkowe, zachowują go na później.

Krótki przykładowy serwer nie jest przeciekającą pamięcią. Uruchomiłem 14-minutowy test z węzłem v0.10.29; wykorzystanie pamięci powoli rośnie tylko początkowo, a następnie zatrzymuje się. Tempo wzrostu jest mniejsze niż jeden bit na połączenie http, więc nie może przeciekać pamięci w samych połączeniach. Może być możliwe, że fragmentacja pamięci spowodowana przez środowisko uruchomieniowe nodejs może doprowadzić do wzrostu sterty, dopóki nie będzie wystarczającej ilości wolnej pamięci, aby nadrobić fragmentację.

Po 14 minutach proces nodejs nadal zużywał tylko 2 MB z 21-sto dziennej sterty, jak na początku. (14 ponieważ 15-minutowy przebieg został zatrzymany na 1:09)

Oto wzrost ponad 2,46 miliona połączeń HTTP (pokazujących tylko stertę wszystkich zmian i ostateczny. Ostateczny ślad pamięci osiąga się po 4 minutach i nie zmienia się przez kolejne 11 min):

2014-12-03T04: 52: 48.358Z {rss: 12222464, heapTotal: 7130752, heapUsed: 1751228}
2014-12-03T04: 52: 55.182Z {rss: 17326080 , heapTotal: 9227904, heapUsed: 2186528}
2014-12-03T04: 53: 59.488Z {rss: 21172224, heapTotal: 13422208, heapUsed: 2092796}
2014-12-03T04: 56: 58.897Z {rss: 29556736 , heapTotal: 21810816, heapUsed: 2100000 }
(...zostało wstrzymane do 1:09 około 05:02:27)
2014-12-03T05: 07: 45.598Z {rss: 29446144, heapTotal: 21810816, heapUsed: 2138608}

my (lekko zmodyfikowany) Test:

var ncalls = 0; 
var http = require('http'); 
http.createServer(function (req, res) { 
    res.writeHead(200, {'Content-Type': 'text/plain'}); 
    res.end('Hello World\n'); 
    if (ncalls++ % 100000 === 0) { 
    global.gc(); 
    console.log(new Date().toISOString(), process.memoryUsage()); 
    } 
}).listen(3000, '127.0.0.1'); 
console.log("Listening on 3000...");