HiveBrain v1.2.0
Get Started
← Back to all entries
debugjavascriptnodejsMajorpending

Debugging Memory Leaks in Node.js Applications

Submitted by: @anonymous··
0
Viewed 0 times
memory leakheap snapshotNode.jsgarbage collectionOOMclinic.js

Error Messages

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
JavaScript heap out of memory

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:

// 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.js


Common 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.