Что делать с ошибкой «Heap out of memory» в JavaScript
В JavaScript ошибка «Heap out of memory» возникает из-за недостатка памяти. Разбираемся в причинах и предлагаем способы решения проблемы.
32К открытий37К показов
Ошибка «Heap out of memory» в JavaScript возникает когда приложению недостаточно памяти. В этой статье мы разберемся как быстро исправить эту ошибку.
Как исправить «Heap out of memory» в JavaScript
Самый быстрый способ — увеличить количество памяти в Node.js. Начиная с версии v8 вы можете устанавливать ограничение в мегабайтах с помощью флага --max-old-space-size
:
Вы можете установить любое ограничение, но не используйте всю доступную память, иначе может произойти крэш системы.
Аналогичного эффекта можно добиться с помощью другого флага:
Изменение ограничения памяти для всей среды Node.js
Чтобы изменить лимит памяти для всей среды, нужно установить значение переменной NODE_OPTIONS в конфигурационном файле (его расширение .bashrc, bash_profile или .zshrc и т. п.).
«Heap out of memory» во время nmp install
Если во время установки пакетов с помощью npn или yarn у вас появляется эта ошибка, вы можете увеличить лимит памяти на время установки.
Что означает эта ошибка?
По умолчанию в Node.js установлен лимит памяти, который не позволяет программе занять слишком много памяти и уронить всю систему. Лимит отличается на разных версиях Node.js и архитектурах (32бита или 64бита).
Ограничения памяти на разных версиях Node.js
Эти значения не объявлены официально, но с помощью небольшой программы можно получить такие значения для 64 битной архитектуры.
Чтобы проверить лимит памяти вашей системы, создайте файл index.js и добавьте в него следующий код:
Как избежать недостатка памяти в Node.js
Увеличение лимита памяти поможет быстро исправить проблему, но этого может быть недостаточно. В следующий раз память системы может закончиться. В любом случае стоит выяснить источник проблемы.
Вот три альтернативных решения, которые позволят уменьшить потребление памяти.
Обработка данных по частям
Иногда нужно обработать большой набор данных. Например, вы пишите программу, которая принимает данные из CSV файла, очищает их и добавляет в БД (это называется ETL: извлечение, трансформация, загрузка).
Если в такой ситуации программе начинает не хватать памяти, попробуйте разделить данные на несколько частей.
Подробнее о том, как сделать это в MongoDB в этом ответе на StackOverflow.
Избегайте утечек памяти
В этой статье объясняется, как работает управление памятью в JavaScript, и как избежать большинства возможных утечек.
Её содержание сводится к тому, что большинство утечек, которые можно отследить, вызваны неудалёнными ссылками на объекты, которые больше не нужны. Это может случиться, когда вы забыли удалить interval, timer или чрезмерно используете глобальные переменные.
Профилирование
Профилирование помогает обнаружить утечки памяти. На фронтенде это можно сделать в Chrome в Инструментах разработчика во вкладке Memory.
В Node.js начиная с версии 6.3.0 также можно использовать Chrome для отладки использования памяти.
Во-первых, запустите приложение в режиме проверки:
Затем откройте страницу в Chrome, введите адрес chrome://inspect
и нажмите на кнопку Open dedicated DevTools for Node.
После этого откроется окно, в котором вы сможете подключиться к вашему Node.js приложению.
Перезапуск процессов
Допустим, ваша программа работает на компьютере с ограниченным объёмом памяти, например Raspberry Pi.
Мы будем использовать cluster и библиотеки node v8.
Cluster даёт возможность воспользоваться преимуществами многоядерных систем и запускать кластер из процессов Node.js.
V8 предоставляет API для конкретной версии V8, используемой в Node.js.
Давайте разделим программу на две сущности: master и worker.
Master будет перезапускать worker`ов в случае, если они перестанут работать из-за переполнения кучи. Worker`ы будут отвечать за основную логику (в нашем случае запускать тяжёлую функцию heavyHeapConsumer).
При первом запуске приложения создается worker и подписка на событие exit, при срабатывании которой создаётся новый worker, и событие логгируется.
total_heap_size — размер кучи, который можно увеличить.
heap_size_limit — максимально возможный размер кучи.
В коде worker`а устанавливается total_heap_size равный 85% от heap_size_limit. Затем worker каждую секунду проверяет не превышен ли лимит. Если лимит превышен, то процесс worker убивает себя.
Лимит (85%) и интервал проверки (1 секунда) нужно выбирать для каждого конкретного случая. Здесь функция heavyHeapConsumer увеличивает кучу каждые 100мс. Если в вашем варианте увеличение будет происходить каждые 10мс, то следует уменьшить лимит и увеличить интервал проверки.
Полный код примера доступен на GitHub.
32К открытий37К показов