
Вы когда-нибудь участвовали в каком-либо крупномасштабном приложении NodeJs? Если да, значит, вы знаете, о чем мы говорим, если нет, то вам нужно продолжить чтение, так как вы можете столкнуться с этим в ближайшее время, как это сделал я 😄. Утечка памяти очень распространена в приложениях NodeJs, особенно в крупномасштабных с разумным трафиком, и многие крупные компании пострадали от этого. дайте знать, почему?
Приложения NodeJs - это длительные процессы, приложение запускается один раз, затем запускается и работает, непрерывно обрабатывая все входящие запросы и потребляя ресурсы.
В отличие от PHP, который создает дочерний процесс для каждого входящего запроса, запускает для него приложение, и после выполнения запроса процесс завершается, и все ресурсы освобождаются.
Этот факт дает преимущества приложений NodeJS, поскольку приложение запускается только один раз, а не для каждого входящего запроса, и при запуске вы можете добавить все свои конфигурации, соединения с БД, маршруты и т. Д. Это ускоряет обработку запросов, поскольку оно выполняет только логику для каждого запроса. без необходимости в повторяющейся работе, а также экономит ресурсы, необходимые для этого процесса запуска.
Но ничто не обходится без платы, поскольку за это преимущество вы должны позаботиться об использовании памяти вашим приложением, поскольку оно будет постоянно потреблять вашу память во время выполнения, и если вы не справляетесь с использованием памяти эффективно, у вас может закончиться памяти, то вам придется перезапустить приложение, чтобы освободить память.
Управление памятью в NodeJs:
Управление памятью в NodeJs осуществляется с помощью V8: «, который позволяет запускать JavaScript на сервере вне браузера».
V8 обрабатывает две основные категории памяти:
Стек: в котором хранятся примитивные типы данных: Number, String, boolean, Null, Undefined, Symbol и ссылки на непримитивные типы данных Object.
Куча: хранит непримитивные типы данных: Object.
В V8 сборщик мусора работает в основном с Mark and Sweep алгоритмом:
Он проверяет все пути ссылок объектов на корневой узел ‘, который является объектом global или window. Если какая-либо ссылка не имеет пути к корневому узлу, она будет помечена как мусор и будет удалена позже.

Важное примечание: когда запускается сборщик мусора, он полностью приостанавливает работу вашего приложения, пока не завершит свою работу. поэтому вам нужно свести к минимуму его работу, позаботившись о ссылках на ваши объекты.
Наиболее частые причины:
Согласно тому, что мы объяснили в разделе «Управление памятью», мы можем определить три наиболее распространенных причины утечки памяти, вы должны быть осторожны при их использовании в своем коде.
Глобальные переменные
Поскольку у них есть прямой путь к корневому узлу, они будут оставаться в памяти до тех пор, пока приложение работает, поэтому вам нужно быть осторожным при установке глобальных переменных и объема данных, которые вы им задаете.
Множественные ссылки
Установка нескольких ссылок на один и тот же объект может вызвать проблему, так как вы можете удалить одну ссылку и забыть о другой, которая сохранит ваш объект в куче.
Закрытие
В замыканиях вы просто сохраняете ссылки на объекты, которые будут использоваться позже. эта функция имеет много преимуществ, но если ее использовать без осторожности, это может вызвать большие проблемы, поскольку эти ссылки будут держать объекты в куче, и эти объекты могут быть большими, а не просто объектами.
Как обнаружить

Существует множество инструментов и библиотек, используемых для обнаружения утечек памяти в NodeJS, все они следуют одной и той же концепции обнаружения утечек памяти путем сравнения различных дампов кучи и проверки результатов, и они пытаются принудительно запустить сборщик мусора перед тем, как сделать какой-либо дамп кучи. уверен, что утечка реальна.
Разница между двумя дампами кучи является индикатором объема утечки памяти в вашем приложении. Я бы выбрал два из этих инструментов, самые важные, с моей точки зрения:
- Node-Memwatch: очень полезен в производстве, поскольку он генерирует определенные события при ненормальном использовании памяти или потенциальной утечке в вашем приложении, чтобы вы могли обработать эти события или ожидать, что возникнет проблема😄.
- Node-Inspector: очень полезен, особенно при использовании с Chrome DevTools на этапе разработки, поскольку он позволяет выполнять стресс-тесты для вашего приложения и контролировать производительность использования памяти, чтобы проверить, есть ли потенциальная утечка в свой код и найдите, где именно может произойти утечка.
Быстрая демонстрация Node-Inspector и Chrome DevTools:
- Во-первых, запустите приложение с параметрами:
expose-gc, чтобы иметь возможность явно запускать сборщик мусора,inspect=9222, чтобы иметь возможность прикрепить отладчик Chrome к вашему приложению через порт9222
, чтобы команда была :node --expose-gc --inspect=9222 app.js - теперь откройте этот URL
chrome://inspectв Chrome, чтобы открыть инспектор устройств Chrome

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

после добавления вашего сервера в список он появится в удаленных целях. просто нажмите inspect.

это откроет новое специальное окно для отладки вашего приложения. на вкладке «Память» вы найдете возможность собирать мусор, делать снимки кучи и отслеживать временную шкалу распределения.
На скриншоте ниже вы можете найти в верхнем левом углу кнопку для принудительного запуска сборщика мусора и кнопку посередине для создания снимков кучи.

Теперь нам нужно сделать два снимка: один в начале, а другой после нескольких вызовов сервера для определенного маршрута, если вы хотите проверить конкретную логику или несколько случайных маршрутов, если вы хотите проверить общую производительность.
а также не делайте этого. Не забывайте принудительно запускать сборщик мусора перед каждым снимком.

После создания второго снимка вверху появляется меню выбора.
Выберите из этого Objects allocated between Snapshot1 and Snapshot2, чтобы увидеть разницу между двумя снимками, поскольку эти объекты являются потенциальной утечкой в вашем приложении.

Вы найдете два раздела для конструкторов и фиксаторов. Сначала вы сосредоточитесь на конструкторах без фигурных скобок, а затем можете проверить другие.

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

Важное замечание: попробуйте сделать много снимков кучи и между ними сделать несколько запросов к вашему серверу и проверить, увеличивается ли использование памяти или остается прежним, если оно стабильно, чтобы вы были в безопасности, иначе у вас возникнут проблемы.
Наконец, это был всего лишь краткий обзор основных частей проблемы утечки памяти. Мы можем поговорить более подробно по каждой части из них, но я хотел сделать краткий обзор этой загадочной темы, поэтому, если вы нравится, покажи свою поддержку хлопками и поделись.
Использованная литература:
- https://blog.risingstack.com/finding-a-memory-leak-in-node-js/
- https://www.toptal.com/nodejs/debugging-memory-leaks-node-js-applications
- Https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/
- Https://www.alexkras.com/simple-guide-to-finding-a-javascript-memory-leak-in-node-js/
- Https://developer.chrome.com/devtools/docs/memory-analysis-101