#Симптомы и условия возникновения
Подозрение на утечку памяти в Node.js возникает, если процесс после одинаковых нагрузочных циклов всё больше потребляет память. Нужно сравнивать heapUsed, external и rss, а не ориентироваться только на один график ОЗУ. Для начала проверьте используемую версию среды и точный текст ошибки на копии проекта, не меняя рабочий сервер.
#Причины и как их отличить
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Удерживаются объекты JavaScriptВ этой ситуации наблюдается конкретный диагностический признак. Сопоставьте его с журналом ошибки и результатом соответствующей проверки, прежде чем выбирать исправление. | Рост heapUsed после повторных одинаковых циклов | Сравнить heap snapshot и пути удержания объектов. |
| Накапливаются Buffer/нативные объектыВ этой ситуации наблюдается конкретный диагностический признак. Сопоставьте его с журналом ошибки и результатом соответствующей проверки, прежде чем выбирать исправление. | RSS/external растут быстрее heapUsed | Посмотреть буферы, потоки, нативные зависимости. |
| Кэш ожидаемо разогреваетсяВ этой ситуации наблюдается конкретный диагностический признак. Сопоставьте его с журналом ошибки и результатом соответствующей проверки, прежде чем выбирать исправление. | Память повышается и стабилизируется | Сравнить длинный период, не объявлять нормальный кэш утечкой. |
#Пошаговая диагностика и решение
- 1. Составьте воспроизводимый тестСоздайте копию приложения без персональных данных и одинаковый сценарий запросов из нескольких циклов. Выберите интервалы покоя между ними; разная нагрузка делает вывод об утечке ненадёжным.
- 2. Начните с малого — измерений памятиДобавьте
process.memoryUsage()в журнал тестового процесса раз в минуту и посмотрите heapUsed, rss, external. Без контекста нагрузки отдельное число не доказывает утечку.
- 3. Проверьте кэши и подпискиПоиск по проекту: Map, Set, массивы, setInterval,
.on(. Убедитесь, что удаляются старые записи, обрабатываются close/end, а listeners не добавляются при каждом запросе без снятия.
- 4. Сделайте два снимка кучи на тестовой копииЧерез
node --inspectподключите Chrome DevTools только к локальной среде, откройте Memory и снимите Heap snapshot после стабилизации и после нескольких одинаковых циклов. Снимки могут быть крупными и содержать секреты.
- 5. Найдите удерживающие ссылкиВ сравнении снимков сортируйте по росту retained size, исследуйте retainers — например, глобальный Map или неочищенный closure. Нельзя полагаться только на число объектов без контекста сборки мусора.
- 6. Исправьте жизненный цикл обнаруженных объектовДобавьте срок хранения и предел размера кэша, снимайте слушатели, закрывайте потоки, устраняйте очереди без ограничений. Для подозрения на нативный пакет используйте поддерживаемые диагностические средства его разработчика.
- 7. Проверьте до длительного развёртыванияПовторите точно такой же тест на исправленном коде, сравните кривые памяти и частоту сборок. Если рост сохраняется, верните код и расширьте диагностический набор, не повышая лимит кучи бесконечно.
#Как проверить результат и что делать, если не помогло
После повторных одинаковых циклов память выходит на устойчивый диапазон либо обоснованно освобождается; у приложения нет новых ошибок OOM и просадки пропускной способности.
Если неисправность повторилась, выпишите первый код ошибки и действие, на котором она возвращается. Сравните версию Node.js/npm, рабочий каталог, настройки процесса и журнал тестового запуска. Откатите только внесённые изменения из предварительно сохранённой копии, затем разберите причину на отдельной среде.