debugjavascriptnodejsMajorpending
Debugging Memory Leaks in Node.js Applications
Viewed 0 times
memory leakheap snapshotNode.jsgarbage collectionOOMclinic.js
Error Messages
Problem
Node.js application memory usage grows continuously over time, eventually causing OOM crashes or severe garbage collection pauses.
Solution
Step-by-step memory leak debugging:
Common leak sources and fixes:
// 1. Monitor memory usage
setInterval(() => {
const mem = process.memoryUsage();
console.log({
rss: `${(mem.rss / 1024 / 1024).toFixed(1)} MB`,
heapUsed: `${(mem.heapUsed / 1024 / 1024).toFixed(1)} MB`,
heapTotal: `${(mem.heapTotal / 1024 / 1024).toFixed(1)} MB`,
external: `${(mem.external / 1024 / 1024).toFixed(1)} MB`,
});
}, 10000);
// 2. Take heap snapshots
// Start with: node --inspect app.js
// Chrome DevTools: chrome://inspect -> Take heap snapshot
// Compare two snapshots to find growing objects# 3. Production heap dump
# Send SIGUSR2 to take heap snapshot (if using heapdump module)
kill -USR2 <PID>
# Or use clinic.js
npx clinic doctor -- node app.js
npx clinic heap -- node app.jsCommon leak sources and fixes:
// LEAK: Event listeners not removed
emitter.on('data', handler); // Accumulates!
// FIX:
emitter.once('data', handler); // Or remove in cleanup
// Monitor: emitter.listenerCount('data')
// LEAK: Closures capturing large scope
function createHandler(hugeData) {
return () => console.log(hugeData.id); // Captures ALL of hugeData
}
// FIX: capture only what you need
function createHandler(hugeData) {
const id = hugeData.id;
return () => console.log(id);
}
// LEAK: Global caches without eviction
const cache = {}; // Grows forever
// FIX: Use LRU cache with max size
const LRU = require('lru-cache');
const cache = new LRU({ max: 1000 });
// LEAK: Unfinished promises/timers
const timers = [];
function startPolling() {
timers.push(setInterval(poll, 1000));
}
// FIX: clear on shutdown
process.on('SIGTERM', () => {
timers.forEach(clearInterval);
});Why
Node.js uses V8's garbage collector which handles most cleanup automatically. Leaks happen when references prevent GC from collecting unused objects. The key is finding what holds those references.
Gotchas
- RSS includes shared libraries and memory-mapped files - heapUsed is the real indicator
- Heap snapshots themselves use a lot of memory - don't take them on memory-constrained production servers
Context
Diagnosing memory leaks in Node.js
Revisions (0)
No revisions yet.