Memory leaks
Тема дорожной карты · Node.js
Утечки памяти в Node.js происходят, когда объекты непреднамеренно сохраняются в куче V8 — как правило, из-за зависших слушателей событий, глобальных переменных, замыканий или растущих кэшей — что приводит к постоянному росту потребления памяти процессом Node.js вплоть до его уничтожения операционной системой или средой выполнения контейнера. Распространённые источники утечек памяти в серверных приложениях Node.js: добавление слушателей EventEmitter внутри обработчиков запросов без вызова removeListener(), накопление записей в Map или массиве в памяти без вытеснения, хранение ссылок на объекты req или res в замыканиях, переживающих запрос, а также сторонние npm-пакеты, не очищающие внутренние ресурсы. Диагностика утечек памяти Node.js обычно включает мониторинг process.memoryUsage().heapUsed во времени, создание снимков кучи с помощью Chrome DevTools Protocol или npm-пакета heapdump и сравнение снимков с флагом --heap-prof или clinic.js heap для выявления растущих типов объектов. Утечку памяти можно подтвердить, наблюдая за монотонным ростом RSS (resident set size) процесса Node.js без соответствующего увеличения реальной нагрузки на данные, и отсутствием снижения RSS после спадов нагрузки. Для предотвращения утечек памяти в Node.js требуется дисциплинированное использование WeakMap для ассоциаций с объектами в качестве ключей, установка emitter.setMaxListeners() для обнаружения избыточной подписки и регулярное проведение нагрузочных тестов с профилированием памяти на стейджинге перед развёртыванием в продакшн.
Как это работает
Memory leaks меряется event-loop lag, latency запросов, throughput, памятью. Инструменты: clinic.js для flame graph, 0x для V8-профилей, autocannon для HTTP-нагрузки, флаг --prof для встроенного профайлера, --inspect для Chrome DevTools. Обычные победы: кешировать горячие SQL-запросы (Redis), избегать sync I/O, переиспользовать HTTP-keepalive (http.Agent), стримить большие ответы вместо буферизации. CPU-профиль почти всегда указывает на одну горячую функцию — её первой.
Когда применять
Меряйте до оптимизации — autocannon против stage-эндпойнта показывает, где стена. Агрессивный кеш на границе (CDN, reverse proxy) и на data-слое (Redis). CPU-тяжёлую работу — в очередь (BullMQ, Redis Streams), чтобы latency запросов оставалась низкой. Для sub-1ms HTTP-оверхеда — Fastify или uWebSockets.js; для всего остального Express + хороший кеш бьёт преждевременные переписывания.
Типичные ошибки
Ловушки Memory leaks: оптимизация без профиля (чините не то); микро-бенчмарки, которые врут (реальная нагрузка другая); игнор утечек памяти до OOM (heapdump + clinic.js); over-cluster на одном хосте (context-switch стоит больше параллелизма после числа CPU). Prometheus/Grafana — с первого дня в production.