Node uses the same V8 JavaScript engine as Chrome, and the same automatic memory management from the earlier JavaScript course's Memory Management lesson — memory is freed once nothing references it anymore. A long-running server makes a leak's consequences far more visible than a browser tab ever does.
A browser tab gets closed and its memory reclaimed completely, often within minutes. A Node server is meant to run for days or weeks — a slow leak that's invisible in a five-minute test becomes a crash from running out of memory after enough traffic.
// LEAK — this Map never removes anything, growing forever
const cache = new Map()
app.get('/users/:id', async (req, res) => {
if (!cache.has(req.params.id)) {
cache.set(req.params.id, await getUser(req.params.id))
}
res.json(cache.get(req.params.id))
})// FIXED — an actual cache needs an eviction strategy
import { LRUCache } from 'lru-cache'
const cache = new LRUCache({ max: 500 }) // keeps at most 500 entries// LEAK — a new listener added on every request, none ever removed
app.get('/subscribe', (req, res) => {
eventEmitter.on('update', (data) => {
res.write(data)
})
})A built-in early warning
Node prints a warning after 10 listeners accumulate on the same event by default — a "MaxListenersExceededWarning" in the console is a strong hint a listener is being added somewhere it's never being removed.
console.log(process.memoryUsage())
// { rss: ..., heapTotal: ..., heapUsed: ..., external: ... }
// heapUsed climbing steadily over time, under steady load, is the signature of a leaknode --inspect server.js
# Then open chrome://inspect in Chrome to attach DevTools —
# the Memory tab can take a heap snapshot, the same tool used
# for browser-side leak hunting in the earlier JavaScript lesson| Common source | Fix |
|---|---|
| An unbounded cache (a plain object or Map that only grows) | Use an actual cache with a size limit and eviction (LRU) |
| Event listeners added repeatedly, never removed | Call .removeListener() / .off() when done, or use .once() for a one-time listener |
| A module-level array or object that keeps accumulating | Clear or bound it explicitly, or scope it to a request instead of the module |
| A forgotten setInterval | Store the interval ID and clearInterval() it when no longer needed |