What is a memory leak in JS?
1. What is a memory leak
A memory leak is a situation where a program keeps references to objects that are no longer needed, so the garbage collector (GC) cannot free them from memory.
In other words:
An object is no longer used, but "forgotten" references keep it in memory.
2. How the garbage collector (GC) works
JS has automatic garbage collection. The GC periodically looks for "reachable" objects: those you can get to through references.
Anything with no references (unreachable) gets removed. Anything with at least one reference stays in memory.
The leak problem happens when an object is no longer needed, but a reference to it survives somewhere → the GC still considers it "alive".
3. Common causes of memory leaks in JavaScript
| Cause | Example | What happens |
|---|---|---|
| Global variables | window.obj = { big: 'data' } | live until the tab closes |
| Uncleared timers / intervals | setInterval(() => {...}, 1000) without clearInterval | the callback keeps a closure and is never freed |
| Event listeners | element.addEventListener('click', handler) without removeEventListener | the element is removed, but the handler stays in memory |
| Closures holding references | functions that close over a context with large objects | the collector cannot free the context |
| Caches and data structures (Map, Set) | a growing Map without clearing old keys | data is never removed automatically |
| DOM references after removing an element | const el = document.getElementById('app'); el.remove();, but the el reference remains | the element is no longer in the DOM, but hangs in memory |
4. Examples of leaks in code
Global variables
function createLeak() {
leak = []; // no let/const -> lands on window
for (let i = 0; i < 1000000; i++) leak.push(i);
}
createLeak();
// leak lives until the tab closesTimers
function start() {
const data = new Array(1e6).fill('data');
setInterval(() => console.log(data.length), 1000);
}
start();
// data is never cleared, it's held by the closureEvent handlers
const btn = document.getElementById('btn');
function handleClick() { console.log('clicked'); }
btn.addEventListener('click', handleClick);
btn.remove(); // but the listener remains
// handleClick and btn stay in memory foreverUnbounded cache
const cache = new Map();
function heavyCalc(key) {
if (cache.has(key)) return cache.get(key);
const result = Array(1e5).fill(key);
cache.set(key, result); // never cleared
return result;
}5. How to detect a memory leak
In the browser (Chrome DevTools)
- Open the Memory tab → "Heap snapshot".
- Take a memory snapshot (Take snapshot).
- Repeat after 10-30 seconds.
- Compare: if "Detached DOM nodes" or objects keep growing → a leak.
You can also open the Performance tab → the "Memory" filter → watch the heap size grow.
In Node.js
--inspectand Chrome DevTools;clinic.js,node --inspect-brk,heapdump;- Monitoring the heap through
process.memoryUsage().
6. How to prevent leaks
| Problem | Solution |
|---|---|
| Global variables | always use let, const |
| Timers | clearTimeout, clearInterval when stopping |
| Event listeners | removeEventListener on unmount |
| Closures | don't keep large objects in scope |
| Caches | clear old entries (WeakMap, WeakSet) |
| DOM | remove references when removing an element |
| SPA apps | watch cleanup in useEffect, onUnmount |
7. "Safe" structures: WeakMap and WeakSet
They do not block the GC, because they hold "weak references".
let cache = new WeakMap();
function getData(obj) {
if (cache.has(obj)) return cache.get(obj);
const data = heavyCalculation(obj);
cache.set(obj, data);
return data;
}If the object obj is no longer used anywhere else, the GC removes it automatically, even if it is still in the WeakMap.
8. Signs of a memory leak
- Gradual application slowdown;
- Growing memory (
Memory→ Heap increasing); - UI lag (especially during scrolling/rendering);
- Frequent garbage collection (GC pauses);
- Tab crashes ("Aw, Snap!") under large data volumes.
9. Quick summary
| What | Description |
|---|---|
| Memory leak | holding unneeded objects in memory |
| Cause | references that are never released |
| Effect | growing memory, lag, crashes |
| Diagnosis | Chrome DevTools (Memory snapshot) |
| Fix | clean up timers, listeners, caches, DOM references |
| Prevention | WeakMap, WeakSet, cleanup hooks |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.