Skip to main content
Practice Problems

How to detect and prevent memory leaks in Node.js?

Memory Leaks in Node.js

A memory leak occurs when the application allocates memory but fails to release it when it's no longer needed. Over time, memory consumption grows until the process crashes with an out-of-memory error.


Common Causes of Memory Leaks

1. Global Variables and Caches Without Limits

js
// โŒ Grows indefinitely const cache = {}; app.get('/data/:id', (req, res) => { cache[req.params.id] = fetchExpensiveData(req.params.id); res.json(cache[req.params.id]); });

Fix: Use LRU cache with a max size:

js
// โœ… Bounded cache const LRU = require('lru-cache'); const cache = new LRU({ max: 500, ttl: 1000 * 60 * 5 });

2. Unremoved Event Listeners

js
// โŒ New listener added on every request app.get('/stream', (req, res) => { process.on('data', handler); // Never removed! });

Fix: Always remove listeners:

js
// โœ… Remove on disconnect req.on('close', () => { process.removeListener('data', handler); });

3. Closures Retaining Large Objects

js
function processData() { const hugeArray = new Array(1e6).fill('data'); // โŒ Closure retains hugeArray even though only length is needed return function getLength() { return hugeArray.length; }; }

Fix: Extract only what's needed:

js
function processData() { const hugeArray = new Array(1e6).fill('data'); const length = hugeArray.length; // hugeArray can now be garbage collected return function getLength() { return length; }; }

4. Forgotten Timers and Intervals

js
// โŒ Interval never cleared setInterval(() => { doSomething(); }, 1000);

Fix: Store and clear references:

js
const interval = setInterval(() => doSomething(), 1000); // When done: clearInterval(interval);

5. Unreferenced Streams

Not consuming readable streams causes buffered data to pile up in memory.


Detecting Memory Leaks

Using process.memoryUsage()

js
setInterval(() => { const mem = process.memoryUsage(); console.log({ rss: `${Math.round(mem.rss / 1024 / 1024)} MB`, heapUsed: `${Math.round(mem.heapUsed / 1024 / 1024)} MB`, heapTotal: `${Math.round(mem.heapTotal / 1024 / 1024)} MB`, external: `${Math.round(mem.external / 1024 / 1024)} MB` }); }, 5000);

Using --inspect with Chrome DevTools

bash
node --inspect server.js

Open chrome://inspect โ†’ Take heap snapshots โ†’ Compare them over time.

Using clinic.js

bash
npx clinic doctor -- node server.js npx clinic heapprofiler -- node server.js

Using --max-old-space-size

bash
# Limit heap to 512MB to catch leaks faster in development node --max-old-space-size=512 server.js

Prevention Checklist

PracticeDescription
Use bounded cachesLRU with max size and TTL
Remove event listenersAlways .removeListener() or .off()
Avoid global stateScope data to request lifecycle
Clear timersclearInterval, clearTimeout
Consume streamsAlways pipe or read streams
Monitor memoryTrack process.memoryUsage() in production
Use WeakMap/WeakRefFor object caches that should not prevent GC

Tip: In production, use monitoring tools like Prometheus + Grafana, Datadog, or New Relic to track memory trends and set alerts before OOM crashes.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems