Сборщик мусора удаляет недостижимые объекты, а не забытые ресурсы. Если ссылка осталась в кеше или обработчике, объект жив. Если соединение или дескриптор не закрыт, память может быть ограничена уже не только V8.
heapUsed и RSS
process.memoryUsage().heapUsed показывает занятую кучу V8, а rss - всю память процесса: код, нативные буферы, стеки и другие области. Рост RSS не всегда означает утечку JavaScript-объектов.
Для первой диагностики снимают метрики до и после одинаковой серии запросов и дают сборке завершиться. Для снимков кучи используют inspector или сигнал --heapsnapshot-signal и сравнивают типы объектов и их retainers.
import { getHeapStatistics } from 'node:v8';
const before = getHeapStatistics();
console.log({
used: before.used_heap_size,
total: before.heap_size_limit,
});
Точное сравнение делают под повторяемой нагрузкой. Один рост после прогрева кеша еще не доказывает утечку.
Четыре источника утечек
Mapили массив без политики вытеснения, куда пишут каждый новый ключ.- Слушатели
EventEmitter, добавленные на запрос и не снятые после завершения. - Замыкания, которые захватывают большой запрос ради одного поля.
- Таймеры, сокеты, workers и файловые дескрипторы без явного завершения.
MaxListenersExceededWarning - полезный сигнал, а не украшение логов. Лимит слушателей не повышают, пока не доказано, что рост является нормальным устройством приложения.
Как подтвердить исправление
Сначала воспроизводят рост на небольшом сценарии, затем убирают одну причину и повторяют тот же сценарий. Успех - возврат памяти и числа слушателей к стабильному уровню после серии циклов, а не меньший пик на одном графике.
Для соединений и workers проверяют не только heap, но и число открытых handles и внешние ресурсы. unref меняет удержание event loop, но не закрывает сам ресурс и не отменяет операцию.
Коротко
heapUsedиrss- разные метрики памяти.- Утечка JavaScript требует достижимой ссылки, утечка ресурса - незавершенной операции.
- Кеши, listeners, замыкания и незакрытые handles проверяют в первую очередь.
- Снимки кучи и retainers помогают найти владельца объектов.
unrefне заменяетclose,clearTimeoutилиterminate.
Что почитать дальше
- Таймауты и отмена - как завершать операции.
- Event-loop lag - как увидеть цену сборки мусора.