advanced

Memory leaks

Find retained references from caches, listeners, timers, closures, global maps, request state, and unbounded queues.

A Node "memory leak" is usually unbounded retention — objects stay reachable via references you forgot to release. RSS grows until OOM kill.

Common retainers:

  • Global Maps caching per user/request without TTL
  • Event listeners never removed (`EventEmitter` on long-lived bus)
  • Closures holding large request context
  • Timers and intervals
  • Unbounded job queues
					// Leak: cache grows forever
const cache = new Map();
app.use((req, res, next) => {
  cache.set(req.user.id, heavyObject(req));
  next();
});
				

Diagnose with two heap snapshots under load — compare retained size. Fix with WeakMap where keys are ephemeral, TTL caches, `off`/`removeListener`, and clear timers on shutdown.

On interviews: explain reachability vs "memory leak" in GC languages; listener leak example; how you'd prove fix in staging.

Common pitfalls: conflating normal heap growth with leak; fixing symptoms by raising `--max-old-space-size` only.

The trade-off is balancing simplicity, performance, safety, and operability — name which axis you optimized and what cost you accepted.

Checklist:

  • Bound every cache.
  • Remove listeners on lifecycle end.
  • Snapshot diff methodology.
  • Monitor heap trend after deploy.