Що таке витік пам'яті в JS?
1. Що таке витік пам'яті
Витік пам'яті (memory leak) - це ситуація, коли програма утримує посилання на об'єкти, які вже не потрібні, тому збирач сміття (Garbage Collector) не може звільнити їх з пам'яті.
Іншими словами:
Об'єкт більше не використовується, але через "забуті" посилання залишається в пам'яті.
2. Як працює збирач сміття (GC)
JS має автоматичну збірку сміття. GC періодично шукає "досяжні" об'єкти - ті, до яких можна дістатися за посиланнями.
Усе, до чого немає посилань (недосяжне), видаляється. Усе, на що є хоча б одне посилання, залишається в пам'яті.
Проблема витоків - коли об'єкт більше не потрібен, але десь залишилося посилання на нього → GC вважає його "живим".
3. Типові причини витоків пам'яті в JavaScript
| Причина | Приклад | Що відбувається |
|---|---|---|
| Глобальні змінні | window.obj = { big: 'data' } | живуть до закриття вкладки |
| Неочищені таймери / інтервали | setInterval(() => {...}, 1000) без clearInterval | колбек утримує замикання і не звільняється |
| Слухачі подій | element.addEventListener('click', handler) без removeEventListener | елемент видалено, але обробник лишився в пам'яті |
| Замикання, що утримують посилання | функції, що замикають контекст із великими об'єктами | збирач не може звільнити контекст |
| Кеші та структури даних (Map, Set) | зростаючий Map без очищення старих ключів | дані не видаляються автоматично |
| DOM-посилання після видалення елемента | const el = document.getElementById('app'); el.remove();, але посилання el лишилося | елемента вже немає в DOM, але він висить у пам'яті |
4. Приклади витоків у коді
Глобальні змінні
function createLeak() {
leak = []; // без let/const → потрапляє у window
for (let i = 0; i < 1000000; i++) leak.push(i);
}
createLeak();
// leak живе до закриття вкладкиТаймери
function start() {
const data = new Array(1e6).fill('data');
setInterval(() => console.log(data.length), 1000);
}
start();
// data ніколи не очищається - утримується замиканнямОбробники подій
const btn = document.getElementById('btn');
function handleClick() { console.log('clicked'); }
btn.addEventListener('click', handleClick);
btn.remove(); // але слухач лишився
// handleClick і btn назавжди залишаться в пам'ятіКеш без ліміту
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); // ніколи не очищається
return result;
}5. Як виявити витік пам'яті
У браузері (Chrome DevTools)
- Відкрий вкладку Memory → "Heap snapshot".
- Зроби знімок пам'яті (Take snapshot).
- Повтори через 10-30 секунд.
- Порівняй: якщо "Detached DOM nodes" або об'єкти зростають → витік.
Також можна ввімкнути вкладку Performance → фільтр "Memory" → дивитися на зростання heap size.
У Node.js
--inspectі Chrome DevTools;clinic.js,node --inspect-brk,heapdump;- Моніторинг heap через
process.memoryUsage().
6. Як запобігати витокам
| Проблема | Рішення |
|---|---|
| Глобальні змінні | завжди використовувати let, const |
| Таймери | clearTimeout, clearInterval при зупинці |
| Слухачі подій | removeEventListener при демонтуванні |
| Замикання | не зберігати великі об'єкти в області видимості |
| Кеші | очищати старі записи (WeakMap, WeakSet) |
| DOM | при видаленні елемента прибирати посилання на нього |
| SPA-застосунки | стежити за cleanup у useEffect, onUnmount |
7. "Безпечні" структури: WeakMap і WeakSet
Вони не заважають GC, бо зберігають "слабкі посилання".
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;
}Якщо об'єкт obj більше ніде не використовується, GC видалить його автоматично, навіть якщо він є у WeakMap.
8. Ознаки витоку пам'яті
- Поступове уповільнення застосунку;
- Зростання пам'яті (
Memory→ Heap increasing); - Затримки в UI (особливо при скролі/рендері);
- Часті збірки сміття (GC pauses);
- Падіння вкладки ("Aw, Snap!") при великих обсягах даних.
9. Коротке резюме
| Що | Опис |
|---|---|
| Memory leak | утримання непотрібних об'єктів у пам'яті |
| Причина | посилання, які не звільняються |
| Наслідок | зростання пам'яті, лаги, падіння |
| Діагностика | Chrome DevTools (Memory snapshot) |
| Рішення | чистити таймери, слухачі, кеші, DOM-посилання |
| Профілактика | WeakMap, WeakSet, cleanup-хуки |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.