Suggest an editImprove this articleRefine the answer for “What is a memory leak in JS?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)A **memory leak** is a situation where a program keeps references to objects that are no longer needed, so the garbage collector cannot free them from memory. **Key point:** the object is no longer used, but "forgotten" references keep it in memory.Shown above the full answer for quick recall.Answer (EN)Image## 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 ```javascript 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 closes ``` --- ### Timers ```javascript 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 closure ``` --- ### Event handlers ```javascript 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 forever ``` --- ### Unbounded cache ```javascript 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) 1. Open the **Memory** tab → "Heap snapshot". 2. Take a memory snapshot (Take snapshot). 3. Repeat after 10-30 seconds. 4. 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 - `--inspect` and 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"**. ```javascript 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 |For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.