Потребление памяти NodeJS в бесконечном цикле - PullRequest
13 голосов
/ 26 октября 2011

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

Вот код:

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

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

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

Ответы [ 3 ]

10 голосов
/ 26 октября 2011

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

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

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

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

6 голосов
/ 26 октября 2011

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

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

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

5 голосов
/ 12 мая 2013

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

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

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

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

Проверьте также эти вопросы и ответы: setImmediate против nextTick

...