Что делать с ошибкой «Heap out of memory» в JavaScript

Ошибка «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 битной архитектуры.

4GB памяти в куче будет достаточно для большинства случаев
Чтобы проверить лимит памяти вашей системы, создайте файл 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мс, то следует уменьшить лимит и увеличить интервал проверки.
Solved: How to Fix “JavaScript Heap Out of Memory Error”

JavaScript remains one of the most-used programming languages due to its versatility. To run JavaScript outside a browser environment, developers must install Node.js, a cross-platform run-time environment.
The JavaScript heap out of memory error is common when running a JavaScript Node.js project.
JavaScript heap out of memory problem is an error that occurs when the default memory allocated by the computer system is insufficient to run a big project.
If you encounter the heap out of memory error, your program will crash and display this output;
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed — JavaScript heap out of memory
Fatal error: invalid table size allocation failed — javascript heap out of memory
Causes of JavaScript heap out of memory error
- Presence of large data structures: Working with large data structures such as matrices or arrays can consume a lot of space, eventually causing heap out of memory error.
This is an example of a large data structure with one billion elements;
- Poor memory management: As your application grows, you need to let go of some of the objects that you no longer need.
This is an example of a function that leads to memory leak;
- Infinite loops: Such a code runs forever as a terminating condition is never reached.
This is an example of an infinite loop that will execute forever;
Infinite loops can lead to this error as it uses memory pretty fast.
- Recursive functions: A recursive function is a function that calls itself indirectly or directly to repeat an/ certain set of instruction(s) until a certain condition(s) is/are met. If these functions are well-designed, they will likely lead to memory lead and, eventually heap of memory error.
- Presence of many objects in a piece of code: If your code has many large objects, the memory used up by those objects collectively can lead to an overload.
Fix JS heap out of memory error
This error can occur in Windows, macOS, and Linux-based operating systems like Ubuntu. Luckily, the error is fixable, irrespective of your operating system.
#1. Fixing the JavaScript heap out of memory error on Windows OS
Step 1: Click on start menu and locate Advanced System Settings .
Step 2: Click on the Environment Variables on the bottom left part of the dialogue box.

Step 3: Click New on either User variables or System variables . The first option applies the changes to the current user account. However, the second option applies the changes to the entire system.

Step 4: There will be two options displayed; on variable name , enter NODE_OPTIONS and on Variable value , enter —max-old-space-size=4096 . In this step, the 4096 figure will allocate 4GB virtual memory to Node.js. You can allocate more such as 8GB, by setting the value as –max-old-space-size=8192.

Step 5: Click ok , apply and finally, ok to save the changes.
You can also use the Windows PowerShell terminal to solve the error. Open the terminal on your Windows OS and enter the following command;

You can also solve the error temporarily by running this command before running your app;
#2. Fixing JavaScript heap out of memory error on Linux
- Step 1: Identify the source of error. Check the console logs or output to determine the lines of code/ file causing the error.
- Step 2: Export an environment variable specifying the virtual memory you have allocated to Node.js. Use this command;
These steps will allocate 4GB virtual memory to Node.js. If the error still persists, you can increase the memory size by doubling.
For instance, if you want to allocate 8GB as the virtual memory, you can run this command;
#3. Fixing JavaScript heap out of memory error on macOS
You can solve the JavaScript heap out of memory error in macOS using a similar approach as in Linux. Follow these steps;
- Step 1: Identify the source of error by checking the console logs or output to determine the lines of code/ file causing the error.
- Step 2: Export an environment variable specifying virtual memory you have allocated to Node.js. Use this command;
These steps will allocate 4GB virtual memory to Node.js. If the error still persists, you can increase the memory size by doubling.
For instance, if you want to allocate 8GB as the virtual memory, you can run this command;
Increasing memory during NPM install
The solutions we have offered so far suit errors that occur when you run a Node.js application. However, you can allocate virtual memory to solve heap out of memory error as you install JavaScript packages. Use this command;
Note: You can keep increasing virtual memory allocation by 1GB, 2GB, 3GB or 4GB. You must specify memory size in MBs. However, don’t allocate the entire memory of machine to the Node.js as this may cause your program to crash. As a good practise, if your machine has 16GB, you can allocate up to 8GB to Node.js.
Prevent JavaScript the heap out of memory error
We have so far discussed how to fix the JavaScript heap out-of-memory error when it occurs. Luckily, you can also have measures to prevent this error from occurring as you run JavaScript code. These are some of the best approaches:
#1. Split data into small chunks
You may have a Node.js program that imports large datasets from large CSV files through the ETL: Extract – Transform – Load process. You may find that your app always crashes when you try to import the data. If you are working with MongoDB, you can solve the error by having a command line instruction such as;
This command instructs Node.js to split a file named users into multiple files with 1000000 users each. The -l flag specifies that the file should be split based on the number of lines of code.
#2. Monitor memory usage
You can use a memory profiler to detect memory leaks in your code. You can combine Node.js’ inbuilt memory and the ChromeDevTools to achieve this. The two can detect issues in your code and fix them.
You can also use external tools such as Datadog, New Relic and AppDynamics to monitor the performance of your app and take the necessary action. You can also check memory usage on your Node.js app through the process.memoryUsage() method.
#3. Avoiding memory leaks
Memory leaks occur when your Node.js app retains references to objects that it no longer needs. If such objects are not garbage collected, there will be a build-up of memory usage over time.
There are several approaches to avoid memory leaks, such as avoiding global variables in your code, avoiding blocking I/O operations, and using let and const keywords when declaring your variables instead of var .
#4. Spawning processes
If you are running Node.js on a machine with limited memory, such as Raspberry Pi, you are likely to run into heap out of memory errors. You can have one master process, and others are grouped as workers. As soon as the master process detects that the system is running out of memory, it will kill that process and assign the task to another one that is not overloaded.
#5. Update hardware
If increasing memory allocation and carrying the listed processes of preventing heap out of memory error don’t solve your problems, then you may consider updating your hardware. Node.js can run on RAM as low as 512MB. However, your app will demand more RAM as it grows.
On the other hand, increasing the number of CPUs can also improve memory allocation. Ideally, 2 or more CPUs will allow your application to use worker threads for CPU-intensive tasks such as cryptography and image processing.
This error can be caused by several reasons;
1. Memory leaks
2. Infinite loops
3. Presence of many objects in a project
4. Presence of large data structures
Как исправить ошибку «JavaScript Heap Out of Memory»

JavaScript остается одним из наиболее часто используемых языков программирования благодаря своей универсальности. Чтобы запускать JavaScript вне среды браузера, разработчики должны установить Node.js, кроссплатформенную среду выполнения.
Ошибка «Недостаточно памяти в куче JavaScript» часто встречается при запуске проекта JavaScript Node.js.
Проблема нехватки памяти в куче JavaScript — это ошибка, которая возникает, когда памяти по умолчанию, выделенной компьютерной системой, недостаточно для запуска большого проекта.
Если вы столкнетесь с ошибкой heap of memory, ваша программа рухнет и отобразит этот вывод;
НЕУСТРАНИМАЯ ОШИБКА: CALL_AND_RETRY_LAST Не удалось выделить — кучи JavaScript не хватает памяти
Неустранимая ошибка: не удалось выделить неверный размер таблицы — куча javascript не хватает памяти
Причины ошибки кучи JavaScript из-за нехватки памяти
- Наличие больших структур данных. Работа с большими структурами данных, такими как матрицы или массивы, может занимать много места, что в конечном итоге приводит к ошибке «кучи не хватает памяти».
Это пример большой структуры данных с одним миллиардом элементов;
- Плохое управление памятью: по мере роста вашего приложения вам нужно избавиться от некоторых объектов, которые вам больше не нужны.
Это пример функции, которая приводит к утечке памяти;
- Бесконечные циклы: такой код работает вечно, так как условие завершения никогда не достигается.
Это пример бесконечного цикла, который будет выполняться вечно;
Бесконечные циклы могут привести к этой ошибке, поскольку они довольно быстро используют память.
- Рекурсивные функции: Рекурсивная функция — это функция, которая косвенно или напрямую вызывает себя для повторения определенного набора инструкций до тех пор, пока не будет выполнено определенное условие (условия). Если эти функции хорошо спроектированы, они, скорее всего, приведут к опережению памяти и, в конечном итоге, к куче ошибок памяти.
- Наличие большого количества объектов в фрагменте кода. Если в вашем коде много больших объектов, память, совместно используемая этими объектами, может привести к перегрузке.
Исправить ошибку кучи JS из-за нехватки памяти
Эта ошибка может возникать в операционных системах Windows, macOS и Linux, таких как Ubuntu. К счастью, ошибка поправима, независимо от вашей операционной системы.
№1. Исправление ошибки памяти JavaScript в куче в ОС Windows
Шаг 1: Нажмите на меню «Пуск» и найдите «Дополнительные параметры системы».
Шаг 2: Нажмите Переменные среды в нижней левой части диалогового окна.
Шаг 3: Нажмите «Создать» для пользовательских или системных переменных. Первый вариант применяет изменения к текущей учетной записи пользователя. Однако второй вариант применяет изменения ко всей системе.
Шаг 4: Отобразятся два варианта; в имени переменной введите NODE_OPTIONS, а в значении переменной введите –max-old-space-size=4096. На этом этапе цифра 4096 выделит 4 ГБ виртуальной памяти для Node.js. Вы можете выделить больше, например 8 ГБ, установив значение –max-old-space-size=8192.

Шаг 5: Нажмите «ОК», «Применить» и, наконец, «ОК», чтобы сохранить изменения.
Вы также можете использовать терминал Windows PowerShell для устранения ошибки. Откройте терминал в вашей ОС Windows и введите следующую команду;

Вы также можете временно устранить ошибку, выполнив эту команду перед запуском приложения;
№ 2. Исправление ошибки JavaScript в куче нехватки памяти в Linux
- Шаг 1: Определите источник ошибки. Проверьте журналы или выходные данные консоли, чтобы определить строки кода/файла, вызывающие ошибку.
- Шаг 2. Экспортируйте переменную среды, указывающую виртуальную память, выделенную для Node.js. Используйте эту команду;

Эти шаги позволят выделить 4 ГБ виртуальной памяти для Node.js. Если ошибка все еще сохраняется, вы можете увеличить объем памяти, увеличив ее вдвое.
Например, если вы хотите выделить 8 ГБ в качестве виртуальной памяти, вы можете запустить эту команду;
№3. Исправление ошибки JavaScript в куче нехватки памяти в macOS
Вы можете решить ошибку «куча JavaScript из-за нехватки памяти» в macOS, используя тот же подход, что и в Linux. Следуй этим шагам;
- Шаг 1: Определите источник ошибки, проверив журналы консоли или выходные данные, чтобы определить строки кода/файла, вызывающие ошибку.
- Шаг 2. Экспортируйте переменную среды, указывающую виртуальную память, выделенную для Node.js. Используйте эту команду;
Эти шаги позволят выделить 4 ГБ виртуальной памяти для Node.js. Если ошибка все еще сохраняется, вы можете увеличить объем памяти, увеличив ее вдвое.
Например, если вы хотите выделить 8 ГБ в качестве виртуальной памяти, вы можете запустить эту команду;
Увеличение памяти во время установки NPM
Решения, которые мы предлагали до сих пор, подходят для ошибок, возникающих при запуске приложения Node.js. Тем не менее, вы можете выделить виртуальную память, чтобы устранить ошибку нехватки памяти при установке пакетов JavaScript. Используйте эту команду;
Примечание. Вы можете продолжать увеличивать выделение виртуальной памяти на 1 ГБ, 2 ГБ, 3 ГБ или 4 ГБ. Вы должны указать размер памяти в мегабайтах. Однако не выделяйте всю память компьютера для Node.js, так как это может привести к сбою вашей программы. Хорошей практикой является то, что если на вашем компьютере 16 ГБ, вы можете выделить до 8 ГБ для Node.js.
Предотвратить ошибку JavaScript в куче нехватки памяти
До сих пор мы обсуждали, как исправить ошибку нехватки памяти в куче JavaScript, когда она возникает. К счастью, у вас также могут быть меры для предотвращения возникновения этой ошибки при запуске кода JavaScript. Вот некоторые из лучших подходов:
№1. Разделите данные на небольшие фрагменты
У вас может быть программа Node.js, которая импортирует большие наборы данных из больших CSV-файлов с помощью процесса ETL: извлечение — преобразование — загрузка. Вы можете обнаружить, что ваше приложение всегда аварийно завершает работу, когда вы пытаетесь импортировать данные. Если вы работаете с MongoDB, вы можете устранить ошибку с помощью инструкции командной строки, например;
Эта команда указывает Node.js разбить файл с именем users на несколько файлов по 1000000 пользователей в каждом. Флаг -l указывает, что файл должен быть разбит на количество строк кода.
№ 2. Мониторинг использования памяти
Вы можете использовать профилировщик памяти для обнаружения утечек памяти в вашем коде. Для этого вы можете комбинировать встроенную память Node.js и ChromeDevTools. Эти два могут обнаружить проблемы в вашем коде и исправить их.
Вы также можете использовать внешние инструменты, такие как Datadog, New Relic и AppDynamics, для мониторинга производительности вашего приложения и принятия необходимых мер. Вы также можете проверить использование памяти в приложении Node.js с помощью метода process.memoryUsage().
№3. Предотвращение утечек памяти
Утечки памяти происходят, когда ваше приложение Node.js сохраняет ссылки на объекты, которые ему больше не нужны. Если такие объекты не подвергаются сборке мусора, со временем будет накапливаться использование памяти.
Существует несколько подходов к предотвращению утечек памяти, таких как избегание глобальных переменных в вашем коде, избегание блокировки операций ввода-вывода и использование ключевых слов let и const при объявлении ваших переменных вместо var.
№ 4. Нерестовые процессы
Если вы используете Node.js на машине с ограниченным объемом памяти, например на Raspberry Pi, вы, скорее всего, столкнетесь с ошибками нехватки памяти. У вас может быть один главный процесс, а другие сгруппированы как рабочие. Как только главный процесс обнаружит, что системе не хватает памяти, он завершит этот процесс и назначит задачу другому, не перегруженному.
№ 5. Обновление оборудования
Если увеличение выделения памяти и выполнение перечисленных процессов предотвращения ошибки «куча нехватки памяти» не решают ваших проблем, вы можете рассмотреть возможность обновления своего оборудования. Node.js может работать в оперативной памяти объемом от 512 МБ. Однако вашему приложению потребуется больше оперативной памяти по мере его роста.
С другой стороны, увеличение количества процессоров также может улучшить распределение памяти. В идеале 2 или более ЦП позволят вашему приложению использовать рабочие потоки для ресурсоемких задач, таких как криптография и обработка изображений.
Часто задаваемые вопросы
Что вызывает ошибку JavaScript Heap Out of Memory?
Эта ошибка может быть вызвана несколькими причинами;
1. Утечки памяти
2. Бесконечные петли
3. Наличие большого количества объектов в проекте
4. Наличие больших структур данных
Решаема ли ошибка JavaScript Heap Out of Memory?
Да. Вы можете решить ошибку через;
1. Выделение больше виртуальной памяти для Node.js
2. Устранение утечек памяти
3. Оптимизация вашего кода
4. Модернизация вашего оборудования
Как вы можете решить ошибку Heap Out of Memory в приложении React?
React — одна из самых популярных библиотек JavaScript. Найдите файл package.json в корневом каталоге и эти строки в разделе сценариев;
Подведение итогов
Большинство разработчиков привыкли к ошибкам и ошибкам кода, а не к ошибкам времени выполнения, когда они запускают свои программы Node.js. К счастью, вам не о чем беспокоиться, так как ошибка «кучи нехватки памяти» поправима. Мы определили, что такое ошибка JavaScript heap of memory, объяснили, как ее решить и как избежать ее в вашем следующем проекте Node.js.
Далее вы также можете прочитать, как избежать некоторых распространенных ошибок JavaScript.
Решение проблем неправильного использования памяти в Node.js
Недавно в компании Reside Real Estate столкнулись с проблемами: в самые ответственные моменты начал падать Node.js-сервер. Подозрение пало на память. Сотрудники компании прибегли к временным мерам, что позволило избавить от неудобств пользователей, и занялись поисками источника проблем. В результате им удалось найти и устранить неполадки.

Типы проблем с памятью
▍ Утечка памяти
В информатике утечка памяти — это разновидность неконтролируемого использования ресурсов, которая возникает, когда программа неправильно управляет выделением памяти, в результате чего память, которая больше не нужна, не освобождается.
В низкоуровневых языках вроде C утечки памяти часто возникают в ситуации, когда память выделяют, например так: buffer = malloc(num_items*sizeof(double)); , но не освобождают после того, как память больше не нужна: free(buffer); .
В языках с автоматическим управлением освобождением памяти утечки возникают, когда к сущностям, которые больше не нужны, можно получить доступ из исполняющейся программы, или из некоего корневого объекта. В случае с JavaScript, любой объект, к которому можно обратиться из программы, не уничтожается сборщиком мусора, соответственно, место, которое он занимает в куче, не освобождается. Если размер кучи вырастет слишком сильно, возникнет ситуация нехватки памяти.
▍ Чрезмерное использование памяти
В ситуации чрезмерного использования памяти программа занимает гораздо больше памяти, чем ей нужно для решения возложенной на неё задачи. Например, такое может возникнуть тогда, когда ссылки на большие объекты хранят дольше, чем нужно для правильной работы программы, что предотвращает уничтожение этих объектов сборщиком мусора. Подобное случается и тогда, когда в памяти держат большие объекты, которые попросту не нужны программе (это вызывает одну из двух основных проблем, которые мы рассмотрим ниже).
Выявление проблем с памятью
Наши проблемы с памятью проявляли себя вполне очевидным образом, в основном — в виде этого мрачного сообщения из журнала:
Признаки утечки памяти, кроме того, включают в себя уменьшение производительности программы с течением времени. Если сервер периодически выполняет один и тот же процесс, который изначально быстр, а перед отказом постепенно становится медленнее, это, весьма вероятно, говорит об утечке памяти.
Признаки чрезмерного использования памяти обычно выражаются в низкой производительности программ. Однако, чрезмерное использование памяти без утечки со временем не приводит к падению производительности.
Временное решение проблемы
Часто, когда что-то случилось, нет времени на то, чтобы понять суть проблемы и всё исправить. У нас его точно не было. К счастью, есть способы увеличения объёма памяти, выделенной процессу Node. У движка V8 имеется стандартное ограничение памяти равное примерно 1.5 Гб на 64-битных компьютерах. Даже если вы запускаете процесс Node на компьютере, имеющем гораздо больше RAM, это роли не играет, если только вы не увеличите этот лимит. Для того, чтобы увеличить лимит, можно передать процессу Node ключ max_old_space_size . Выглядит это так:
Параметр $SIZE задаётся в мегабайтах и, теоретически, может быть любым числом, которое имеет смысл на конкретном компьютере. В нашем случае был использован параметр 8000, который, с учётом особенностей работы сервера, позволил выиграть достаточно времени на исследования. Кроме того, мы увеличили динамическую память. Мы пользуемся Heroku, там это делается просто.
Также мы воспользовались сервисом Twilio, настроили его так, чтобы нас оповещали каждый раз, когда на сервер приходит запрос, требующий особенно много памяти. Это позволило нам наблюдать за запросом и перезапускать сервер после его завершения. Такое решение неидеально, но для того, чтобы наши пользователи не сталкивались с отказами, мы были готовы на всё, даже на круглосуточные дежурства без выходных.
Отладка
Итак, благодаря настройкам Node и организации мониторинга сервера мы выиграли время, которое можно было потратить на то, чтобы дойти до первопричины неполадки. На первый взгляд может показаться, что «проблема с памятью сервера» — это нечто ужасное, а для избавления от этой «проблемы» потребуются фантастические инструменты и умения. Однако, на самом деле, всё не так уж и страшно. Есть вполне доступные инструменты для исследования приложений, существует множество материалов, в которых можно найти подсказки. Мы, для исследования памяти Node-сервера, будем пользоваться инструментами разработчика Chrome.
▍ Снепшот кучи
«Утечка памяти» — это проблема, которая выражается в постоянно растущем размере кучи. В результате куча оказывается слишком большой для продолжения нормальной работы сервера. Поэтому в самом начале исследования нужно сделать несколько снепшотов (снимков состояния) кучи, с некоторым интервалом, и погрузиться в исследование этих снепшотов с использованием инструментов разработчика Chrome для того, чтобы понять, почему куча так велика и почему она растёт. Обратите внимание на то, что следует делать несколько снепшотов, через некоторое время, в результате можно будет изучить объекты, которые будут переходить из одного снепшота в другой. Эти объекты, вполне возможно, являются виновниками утечки памяти. Существует множество способов создать снепшот кучи.
▍ Использование heapdump для создания снепшотов кучи
Мы, для создания снимков кучи, пользовались heapdump. Этот npm-пакет оказался весьма полезным. Его можно импортировать в код и обращаться к нему в тех местах программы, где нужно делать снепшоты. Например, мы делали снепшот каждый раз, когда сервер получал запрос, который мог вызвать процесс, интенсивно использующий память. Тут же мы формировали имя файла, содержащее текущее время. Таким образом мы могли воспроизводить проблему, отправляя на сервер всё новые и новые запросы. Вот как это выглядит в коде:
▍ Использование удалённого отладчика Chrome для создания снепшотов кучи
Если вы работаете с Node 6.3. или с более поздней его версией, для создания снепшотов кучи можно использовать удалённый отладчик Chrome. Для того, чтобы это сделать, сначала запустите Node командой такого вида: node —inspect server.j s. Затем перейдите по адресу chrome://inspect . Теперь вы сможете удалённо отлаживать процессы Node. Чтобы сэкономить время, можете установить этот плагин Chrome, который автоматически откроет вкладку отладчика при запуске Node с флагом —inspect . После этого просто делайте снепшоты тогда, когда сочтёте это необходимым.

Средства удалённой отладки Chrome и создание снепшотов кучи
Загрузка снепшотов и определение типа проблемы с памятью
Следующий шаг заключается в загрузке снепшотов на закладке Memory (память) инструментов разработчика Chrome. Если вы использовали для создания снепшотов кучи удалённый отладчик Chrome, то они уже будут загружены. Если вы использовали heapdump, то вам понадобится загрузить их самостоятельно. Обязательно загружайте их в правильном порядке, а именно — в том, в котором они были сделаны.
Самое главное, на что надо обращать внимание на данном этапе работы, заключатся в том, чтобы понять — с чем именно вы столкнулись — с утечкой или с чрезмерным использованием памяти. Если перед вами утечка памяти, то вы, вероятно, уже получили достаточно данных для того, чтобы начать исследовать кучу в поисках источника проблемы. Однако, если перед вами — чрезмерное использование памяти, вам нужно попробовать некоторые другие методы анализа для того, чтобы получить содержательные данные.
Наша первая проблема с памятью выглядела, на закладке Memory инструментов разработчика Chrome, так, как показано ниже. Несложно заметить, что куча постоянно растёт. Это говорит об утечке памяти.

Куча увеличивается со временем — очевидная утечка памяти
Наша вторая проблема с памятью, которая возникла через пару месяцев после исправления утечки, в итоге, на тех же испытаниях, выглядела так, как показано на рисунке ниже.

Куча со временем не растёт — это не утечка памяти
Размер кучи со временем не меняется. Всё дело в том, что при чрезмерном использовании памяти её размер превышает некие ожидаемые показатели не всегда, а лишь при выполнении определённых операций. При этом снепшоты делаются в какие-то моменты, которые никак не привязаны к ситуациям с чрезмерным использованием памяти. Если в момент создания снепшота не происходило выполнения неправильно написанной ресурсоёмкой функции, тогда куча не будет содержать никакой ценной информации о памяти, используемой этой функцией.
Для выявления подобных проблем мы рекомендуем два способа, которые помогли нам обнаружить виновников проблемы — функцию и переменную. Это — запись профиля выделения памяти и создание снепшотов на сервере, находящемся под серьёзной нагрузкой.
Если вы используете версию Node 6.3 или более позднюю, вы можете записать профиль выделения памяти через удалённый отладчик Chrome, запустив Node с уже упоминавшимся ключом —inspect . Это даст сведения о том, как отдельные функции используют память с течением времени.

Запись профиля выделения памяти
Ещё один вариант заключается в отправке множества одновременных запросов к вашему серверу и в создании множества снепшотов во время обработки этих запросов (предполагается, что сервер работает асинхронно, как результат, некоторые снепшоты могут оказаться гораздо больше других, что укажет на проблему). Мы бомбардировали сервер запросами и делали снепшоты. Некоторые из них оказались очень большими. Исследованием этих снепшотов можно заняться для выявления источника проблемы.
Анализ снепшотов
Теперь у нас есть данные, которые вполне могут помочь найти виновников проблем с памятью. В частности, рассмотрим анализ ситуации, в которой размеры последовательно сделанных снепшотов растут. Вот один из снепшотов, который загружен на вкладке Memory инструментов разработчика Chrome.

Исследование утечки памяти — все функции указывают на наш сервис электронной почты
Показатель Retained Size — это размер памяти, освобождённой после того, как объект удалён вместе со своими зависимыми объектами, которые недостижимы из корневого объекта.
Анализ можно начать с сортировки списка по убыванию по параметру Retained Size, после чего приступить к исследованию больших объектов. В нашем случае имена функций указали нам на ту часть кода, которая вызывала проблему.
Так как мы были уверены в том, что перед нами утечка памяти, мы знали, что исследование стоит начать с поиска переменных с неподходящей областью видимости. Мы открыли файл index.js почтовой службы и тут же обнаружили переменную уровня модуля в верхней части файла.
Мы со всем этим разобрались, внесли необходимые изменения, протестировали проект ещё несколько раз и исправили в итоге утечку памяти.
Вторую проблему отлаживать было сложнее, но тут сработал тот же подход. Ниже показан профиль выделения памяти, который мы записали с использованием инструментов разработчика Chrome и ключа Node —inspect .

Поиск виновников чрезмерного использования памяти
Так же как при анализе данных в ходе поиска утечки памяти, многие имена функций и объектов с первого взгляда узнать не удаётся, так как находятся они на более низком уровне, чем код, который пишут для Node.js. В подобной ситуации следует, встретив незнакомое имя, записать его.
Профиль выделения памяти привёл нас к одной из функций, recordFromSnapshot , она стала хорошей отправной точкой. Наше исследование снепшота кучи, которое не особенно отличалось от исследования, выполняемого при поиске утечки памяти, позволило обнаружить очень большой объект target . Это была переменная, объявленная внутри функции recordFromSnapshot . Эта переменная осталась от старой версии приложения, она была больше не нужна. Избавившись от неё, мы исправили ситуацию с чрезмерным использованием памяти и ускорили выполнение процесса, которое раньше занимало 40 секунд, до примерно 10 секунд. При этом процессу не требовалась дополнительная память.
Итоги
Две вышеописанные проблемы с памятью заставили нас притормозить развитие нашего проекта, которое до этого шло очень быстро, и проанализировать производительность сервера. Теперь мы понимаем особенности производительности сервера на гораздо более глубоком уровне, чем раньше, и мы знаем, сколько времени нужно для нормального выполнения отдельных функций, и сколько памяти они используют. У нас появилось гораздо лучшее понимание того, какие ресурсы нам нужны при дальнейшем масштабировании проекта. И, что самое важное, мы перестали бояться проблем с памятью и перестали ожидать их появления в будущем.