2015-10-22 44 views
7

My MCVE jest następującyPętla console.log w nodejs

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

Kiedy robię to, w pewnym momencie, mój nodejs prostu przestaje drukować rzeczy, dając mi moc, która wygląda tak

[...] 
684665 
684666 
684667 

A potem, mam to:

<--- 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 

zastanawiałem się, co można zrobić, że console.log może spowodować błąd braku pamięci?

+0

Myślę, że to przepełnia bufor i trzeba go przepłukać – Hristo

+0

@ Chris zredagowałem mój post, to nie był problem z kolorami – tforgione

+0

Może warto otworzyć bilet w repozytorium [NodeJS] (https://github.com/ nodejs/node/issues) link do tego pytania. –

Odpowiedz

2

Po otwarciu problem na nodejs repozytorium, mam following answer:

się spodziewałem, że zachowanie: console.log jest asynchroniczny, pamięć skojarzona z każdym wywołaniem nie może zostać odzyskana do następnego tiku pętli zdarzeń. W twoim przykładzie następny tyk nigdy się nie dzieje z powodu nieskończonej pętli.Jeśli przepisać przykład do podejścia zwrotnego z napędem, to wciąż działa na zawsze:

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

Według tej dyskusji: https://groups.google.com/forum/#!topic/nodejs/KtONbpVV68U

każdym razem dzwonić console.log (lub innej metody rejestrowania), obiekt konsola będzie przeznaczyć trochę pamięci. Pamięć ta będzie wolna od śmieciarza na kolejnym tiku. Ale jeśli masz zbyt dużą pętlę, następny tyk nigdy nie nadejdzie.

Ale mam przetestowane:

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

Według grup dyskusyjnych, między każdym przedziale, NodeJS śmieci kolektor powinien zwolnić przydzieloną pamięć przez console.log. Ale to nie jest. Za każdym razem, gdy pętla jest uruchomiona, mój proces zajmuje więcej pamięci RAM.

Przetestowałem to również:

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++); 
} 

zachowanie jest takie samo. Proces ten zabiera coraz więcej pamięci RAM, aż do awarii (ponieważ dostępnych jest mniej pamięci RAM). Plik stdout.log jest zawsze pusty.

Wreszcie przetestowane:

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) 

Ten przykład jest interesujący. Ponieważ między poszczególnymi interwałami jest napisane stdout.log (linie są dołączane do pliku), a RAM odzyskane przez proces nie rośnie. Pomiędzy kolejnymi przerwami śmieciarz wykonuje swoje prace.

Myślę, że obiekt konsoli nie obsługuje dobrze bufora. Ale wciąż jest dziwne. Jeśli używasz standardowego wyjścia (tylko z numerem console.log), wygląda to tak, że obiekt konsoli jest przechowywany w pamięci. I nigdy się nie oczyszcza. A jeśli użyjesz pliku ouput, wszystko działa dobrze (z wyjątkiem tego, że oczywiście piszesz je w pętli nieskończoności).

Może dlatego, że od wersji NodeJS, pracuję z NodeJS 0.12.7

+0

Twoje pierwsze ' Przykład setInterval nie wydaje się przeciążać mojej pamięci RAM, być może z powodu mojej wersji (4.2.1). – tforgione

+0

Jak wyjść z pętli podłogowej? Mam więcej kodu do wykonania, ale nigdy mu się to nie uda, ponieważ setInterval kontynuuje ostrzał. –

1

Zobacz więcej szczegółów w dyskusji na https://github.com/nodejs/node/issues/11568

Ponadto, jak descibed w dokumentacji konsola jest synchroniczny kiedy stdout przekierowany do pliku. Opisane zachowanie nadal jednak również zostało odtworzone w tym przypadku.

Nieskończona pętla z wynikiem console.log() przekierowanym do pliku nie powoduje awarii węzła v4.x, lecz awarii Node v6. To wygląda na błąd wprowadzony w wersji 6.

Jako tymczasowe obejście można użyć poprawki console-sync.