Ответ
Для диагностики и устранения утечек памяти в Node.js я использую комбинацию инструментов и следующих практик:
1. Профилирование и диагностика:
// Использую встроенный модуль v8 для снимков кучи
const v8 = require('v8');
const fs = require('fs');
function takeHeapSnapshot() {
const snapshot = v8.getHeapSnapshot();
const fileName = `heapdump-${Date.now()}.heapsnapshot`;
const fileStream = fs.createWriteStream(fileName);
snapshot.pipe(fileStream);
console.log(`Heap snapshot saved to ${fileName}`);
}
// Мониторинг в реальном времени
setInterval(() => {
const memoryUsage = process.memoryUsage();
console.log({
rss: `${Math.round(memoryUsage.rss / 1024 / 1024)} MB`,
heapTotal: `${Math.round(memoryUsage.heapTotal / 1024 / 1024)} MB`,
heapUsed: `${Math.round(memoryUsage.heapUsed / 1024 / 1024)} MB`,
external: `${Math.round(memoryUsage.external / 1024 / 1024)} MB`
});
}, 10000);
2. Типичные причины утечек в Node.js:
- Глобальные переменные: Непреднамеренное присвоение больших объектов глобальным переменным
- Таймеры и обработчики событий: Незакрытые
setInterval,setTimeoutили слушатели событий - Замыкания: Сохранение ссылок на большие объекты в замыканиях
- Кэши без ограничений: Кэши, которые растут бесконечно без механизма инвалидации
- Соединения: Незакрытые соединения с базами данных, сокеты или файловые дескрипторы
3. Практические решения:
// Вместо обычного объекта для кэша использую WeakMap
const cache = new WeakMap();
// Для очистки таймеров всегда сохраняю их ID
const timerIds = new Set();
function createManagedInterval(callback, delay) {
const id = setInterval(callback, delay);
timerIds.add(id);
return id;
}
function cleanupTimers() {
timerIds.forEach(id => clearInterval(id));
timerIds.clear();
}
// Использую потоковую обработку для больших данных
const { pipeline } = require('stream');
const { createReadStream, createWriteStream } = require('fs');
async function processLargeFile(inputPath, outputPath) {
await pipeline(
createReadStream(inputPath),
// Трансформации...
createWriteStream(outputPath)
);
}
4. Инструменты, которые я применяю:
node --inspectс Chrome DevTools Memory tab- Clinic.js для комплексного анализа производительности
node --trace-gcдля отслеживания сборки мусораmemwatch-nextдля обнаружения утечек
5. Профилактика:
- Использую линтеры с правилами для обнаружения потенциальных утечек
- Настраиваю лимиты памяти в production (
--max-old-space-size) - Регулярно запускаю нагрузочное тестирование с профилированием памяти