Содержание
Я неоднократно сталкивался с этой пугающе выглядящей ошибкой, когда в моем приложении заканчивалась память.
В этой небольшой статье я расскажу вам о решении, которое можно использовать для быстрого устранения этой проблемы.
После этого, если вы захотите узнать об этом больше, я объясню, каковы могут быть причины этой ошибки и как предотвратить ее появление в будущем.
Как решить ошибку “Heap out of memory” в JavaScript
Самый быстрый способ решить эту проблему - увеличить лимит памяти Node. Начиная с Node.js v8, вы можете установить лимит в мегабайтах с помощью флага --max-old-space-size следующим образом:
node --max-old-space-size=4096 index.js
4096 означает 4 ГБ памяти. Вы можете установить любой лимит, но следите за тем, чтобы не использовать всю доступную память, иначе система может упасть.
В качестве альтернативы можно установить флаг в переменной окружения, например, так:
NODE_OPTIONS="--max-old-space-size=4096" node index.js
Измените ограничения памяти Node.js в вашей среде.
Если вы хотите изменить ограничения памяти Node.js для всего вашего окружения, вам нужно установить следующую переменную в конфигурационном файле вашего окружения. (.bashrc, .bash_profile, иногда .zshrc и т. д.)
Добавьте эту строку в ваш конфигурационный файл:
~/.bashrc export NODE_OPTIONS=--max_old_space_size=4096
“npm install” heap out of memory
Если вы столкнулись с этой проблемой при установке пакета с помощью npm или yarn, вы можете временно обойти ограничение памяти, установив пакет следующим образом:
node --max-old-space-size=4096 $(which npm) install -g nextawesomelib
Что вообще означает эта ошибка?
По умолчанию в Node.js есть ограничения памяти, которые не позволяют программе потреблять слишком много памяти и приводить к краху всей системы. Результаты зависят от версии и архитектуры вашей системы (32- или 64-разрядная).
Ограничения памяти для различных версий Node.js
Официальных цифр относительно этих ограничений нет, но с помощью небольшой программы, которую я написал, я смог получить их для разных версий Node.js на 64-битной архитектуре.
Node VersionLimit15.0.14.03 GB14.15.04.03 GB13.14.02.01 GB12.19.02.01 GB11.15.01.34 GB10.15.31.34 GB9.11.21.35 GB
Как видно из этой таблицы, в некоторых версиях лимиты по умолчанию увеличивались. 4 ГБ кучной памяти обычно достаточно для большинства случаев использования.
Вы можете проверить это самостоятельно, создав файл index.js со следующим кодом и запустив его с версией Node.js, для которой вы хотите узнать предел.
const array = [];
while (true) {
// Это делает массив больше на каждой итерации
array.push(new Array(10000000));
const memory = process.memoryUsage();
console.log((memory.heapUsed / 1024 / 1024 / 1024).toFixed(4), 'GB');
}
Как предотвратить истощение памяти в Node.js
Увеличение лимита памяти - это быстрое решение проблемы, которого в некоторых случаях бывает достаточно. Однако в других случаях в системе может не быть больше памяти, или увеличение лимита устраняет проблему лишь на время.
В любом случае, вам стоит докопаться до сути проблемы и выяснить, чем она вызвана.
Вот три альтернативных решения для снижения потребления памяти, которые я использовал или с которыми сталкивался в свое время.
Разделите обработку данных на более мелкие фрагменты
Бывают случаи, когда вам нужно обработать большие наборы данных. Например, вы написали импортер, который берет данные из CSV-файла, дезинфицирует их и добавляет в базу данных (это также известно как ETL: Extract - Transform - Load).
Если при попытке импортировать большие массивы данных в ваше приложение не хватает памяти, альтернативным решением может стать разбиение данных на более мелкие фрагменты.
# split -l numberoflines filename split -l 1000000 users.csv
Взято из этого ответа на StackOverflow, в котором более подробно объясняется, как это сделать с базой данных MongoDB.
Избегайте утечек памяти
Вашему приложению постоянно не хватает памяти, а увеличение лимита памяти лишь оттягивает время? Скорее всего, в вашем приложении есть утечки памяти.
В предыдущей статье я рассказал о том, как работает управление памятью в JavaScript и как можно предотвратить некоторые из наиболее распространенных утечек памяти.
Подводя итог, можно сказать, что большинство утечек памяти связано с тем, что вы не удалили все ссылки на объекты, которые вам больше не нужны. Это может произойти, когда вы забываете удалить интервалы или таймеры, или чрезмерно используете глобальные переменные.
Профилирование
Профилирование помогает обнаружить утечки памяти. На переднем плане вы можете профилировать использование памяти в Chrome DevTools на вкладке ”Память”.
В Node.js, начиная с версии 6.3.0, вы также можете использовать Chrome для отладки использования памяти. Сначала нужно запустить приложение в режиме проверки:
node --inspect index.js
Затем откройте chrome://inspect в Chrome и нажмите на Open dedicated DevTools for Node. Откроется новое окно отладки, которое автоматически подключится к вашему приложению Node.js.
Порождайте процессы и перезапускайте их, когда у них закончится память
Допустим, вы запускаете свою программу на машине с очень ограниченным объемом памяти, как, например, на Raspberry Pi.
В этой статье рассказывается о том, как порождать новые процессы после того, как у них закончится память.
При таком подходе у нас будет один главный процесс и несколько рабочих. Как только рабочий обнаружит, что у него заканчивается память, мастер убьет этот процесс и использует другой рабочий для обработки основной логики.
Мне показался интересным такой способ решения проблемы, но сам я еще не сталкивался с ситуацией, когда это было бы необходимо.
Заключение
В этой статье я постарался предоставить вам всю необходимую информацию для решения проблемы “JavaScript Heap Out Of Memory”.
Если вы хотите узнать больше о том, как работает JavaScript, я недавно написал эти две статьи об управлении памятью и цикле событий:
JavaScript Event Loop и Call Stack Explained: Куча, стек вызовов и цикл событий - это термины, которые я время от времени слышал и читал, но никогда до конца не понимал. В этой статье я объясню, что они означают и что происходит с нашим кодом, когда движок его выполняет. Управление памятью в JavaScript: Здесь я углубляюсь в то, как работает управление памятью в JavaScript, объясняю, для чего используются куча и стек и как работает сборка мусора.
Читайте оригинал статьи или другие интересные посты в блоге Феликса.