Потребление памяти NodeJS в бесконечном цикле

Я не знаю, является ли это ошибкой с Node или V8, но если я запустил следующий код, процесс узла протекает в памяти. Кажется, что в GC не появляется, и через несколько секунд он потребляет> 1 ГБ памяти. Это неожиданное поведение. Я что-то пропустил?

Вот код:

for(;;) { console.log(1+1); } 

Очевидно, что это немного надуманная ситуация, но я вижу проблему с длительным процессом, который никогда не освобождает память.

Редактирование: я старался как с v0.5.10 (неустойчивый), так и с v0.4.12 (стабильный), а неустойчивая версия работает немного лучше – стабильная версия просто перестает выводить на консоль, но продолжает потреблять память, тогда как стабильная версия продолжает выполнять и потреблять память без паузы.

Вы блокируете цикл событий node.js, никогда не возвращаясь к нему.

Когда вы пишете что-то в stream node.js делает это асинхронно: он отправляет запрос на запись, ставит в очередь информацию о отправленном запросе во внутренних структурах данных streamа и ожидает обратного вызова, который уведомляет его о завершении.

Если вы блокируете цикл событий, обратный вызов никогда не будет вызван (поскольку входящие события никогда не обрабатываются), а вспомогательные структуры данных, поставленные в очередь в streamе, никогда не будут освобождены.

То же самое может произойти, если вы «перегружаете» цикл событий, постоянно планируя собственные события с помощью nextTick / setInterval / setTimeout.

Ответ @VyacheslavEgorov кажется правильным, но я бы предположил, что отсрочка на цикл событий решит проблему. Вы можете сравнить, как ваш бесконечный for-loop сравнивается с этой страtagsей бесконечного цикла:

 function loginf() { console.log(1+1); process.nextTick(loginf); } loginf(); 

Идея состоит в том, чтобы использовать process.nextTick(cb) чтобы отложить до цикла событий и (предположительно) позволить GC выполнять свою задачу.

Поскольку Node.js v0.10 был выпущен, setImmediate следует использовать в качестве первого выбора вместо process.nextTick при вызове рекурсивного обратного вызова.

 function loginf() { console.log(1+1); setImmediate(loginf); } loginf(); 

Потребление памяти этого fragmentа кода оставалось низким (<10 МБ) после работы в течение примерно 15 минут на моем компьютере.

Напротив, запуск бесконечного for loop вызвал выделение памяти и процесс .nextTick выбрал Maximum call stack size exceeded .

Также проверьте этот вопрос: setImmediate vs. nextTick