Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке витік пам'яті в JS?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Витік пам'яті (memory leak)** - це ситуація, коли програма утримує посилання на об'єкти, які вже не потрібні, через що збирач сміття (**Garbage Collector**) не може звільнити їх з пам'яті. **Ключове:** об'єкт більше не використовується, але через "забуті" посилання залишається в пам'яті.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 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. Приклади витоків у коді ### Глобальні змінні ```javascript function createLeak() { leak = []; // без let/const → потрапляє у window for (let i = 0; i < 1000000; i++) leak.push(i); } createLeak(); // leak живе до закриття вкладки ``` --- ### Таймери ```javascript function start() { const data = new Array(1e6).fill('data'); setInterval(() => console.log(data.length), 1000); } start(); // data ніколи не очищається - утримується замиканням ``` --- ### Обробники подій ```javascript const btn = document.getElementById('btn'); function handleClick() { console.log('clicked'); } btn.addEventListener('click', handleClick); btn.remove(); // але слухач лишився // handleClick і btn назавжди залишаться в пам'яті ``` --- ### Кеш без ліміту ```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); // ніколи не очищається return result; } ``` --- ## 5. Як виявити витік пам'яті ### У браузері (Chrome DevTools) 1. Відкрий вкладку **Memory** → "Heap snapshot". 2. Зроби знімок пам'яті (Take snapshot). 3. Повтори через 10-30 секунд. 4. Порівняй: якщо "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**, бо **зберігають "слабкі посилання"**. ```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; } ``` Якщо об'єкт `obj` більше ніде не використовується, GC видалить його **автоматично**, навіть якщо він є у `WeakMap`. --- ## 8. Ознаки витоку пам'яті - Поступове уповільнення застосунку; - Зростання пам'яті (`Memory` → Heap increasing); - Затримки в UI (особливо при скролі/рендері); - Часті збірки сміття (GC pauses); - Падіння вкладки ("Aw, Snap!") при великих обсягах даних. --- ## 9. Коротке резюме | Що | Опис | |---|---| | **Memory leak** | утримання непотрібних об'єктів у пам'яті | | **Причина** | посилання, які не звільняються | | **Наслідок** | зростання пам'яті, лаги, падіння | | **Діагностика** | Chrome DevTools (Memory snapshot) | | **Рішення** | чистити таймери, слухачі, кеші, DOM-посилання | | **Профілактика** | `WeakMap`, `WeakSet`, cleanup-хуки |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.