Script Valley
Debugging: A Systematic Approach
Debugging in Production and Distributed SystemsLesson 6.4

How to debug memory leaks in Node.js applications

memory leaks, heap snapshots, garbage collection, event listener leaks, closure retention, V8 memory tools

What a Memory Leak Looks Like

A memory leak in Node.js manifests as heap memory that grows continuously over time and never decreases. The process eventually crashes with an out-of-memory error or slows to a crawl. The cause is always the same: objects that are no longer needed but remain reachable in the object graph, preventing garbage collection.

Taking and Comparing Heap Snapshots

// Take heap snapshots programmatically
const v8 = require('v8');

// Snapshot before the suspected leak
v8.writeHeapSnapshot('./heap-before.heapsnapshot');

// Run the operation you suspect is leaking
for (let i = 0; i < 1000; i++) await processRequest();

// Snapshot after
v8.writeHeapSnapshot('./heap-after.heapsnapshot');
// Open both in Chrome DevTools under Memory tab, then Load snapshot
// Compare: objects that grew in count are your leak candidates

Common Leak Patterns

The most common Node.js leaks: event listeners added but never removed (call emitter.removeListener when done); closures holding references to large objects after the outer function returns; caches with no eviction policy (use a Map with a size limit or an LRU cache). For event listener leaks, process.on('uncaughtException', handler) inside a request handler is a classic example -- it re-registers on every request and the listeners pile up.

Up next

How to write a postmortem that prevents the bug from recurring

Sign in to track progress

How to debug memory leaks in Node.js applications โ€” Debugging in Production and Distributed Systems โ€” Debugging: A Systematic Approach โ€” Script Valley โ€” Script Valley