Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Збирання сміття в V8». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Garbage Collection** - автоматичне звільнення пам'яті від об'єктів, на які більше немає посилань: V8 позначає (mark) досяжні об'єкти від кореневих посилань, а решту очищає (sweep), поділяючи купу на молоде й старе покоління для ефективності. **Ключове:** GC не звільнить об'єкт, поки на нього лишається хоч одне посилання - звідси й витоки пам'яті через забуті посилання.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 1. Що таке збирання сміття **Garbage Collection (збирання сміття)** - це процес **автоматичного звільнення пам'яті**, яку займають об'єкти, що **більше не використовуються** в програмі. Ідея: > Якщо на об'єкт **немає посилань**, його можна безпечно видалити з пам'яті. Приклад: ```javascript let user = { name: 'Tim' }; user = null; // тепер на об'єкт немає посилань → GC звільнить пам'ять ``` ## 2. Як керується пам'ять у V8 Коли ти створюєш об'єкт, масив, функцію чи рядок, **V8 виділяє під них пам'ять у купі (heap)**. V8 ділить купу на дві частини: 1. **New Space (молоде покоління)** - для недавно створених об'єктів; 2. **Old Space (старе покоління)** - для довгоживучих об'єктів. ## 3. Структура пам'яті у V8 | Область | Призначення | |---|---| | **Stack (стек)** | Локальні змінні й виклики функцій (керується автоматично) | | **Heap (куча)** | Об'єкти, масиви, функції та замикання (керується GC) | | **New Space** | Нові об'єкти, що живуть недовго | | **Old Space** | Об'єкти, що пережили кілька циклів GC | | **Code Space** | Скомпільований машинний код JIT-компілятора | | **Large Object Space** | Для дуже великих об'єктів (наприклад, довгих масивів) | ## 4. Алгоритм роботи збирача сміття V8 використовує **інкрементальні й багатопотокові GC-алгоритми**: Основні етапи - **"Mark and Sweep" (Позначення й Очищення)** ### 1. Mark (позначення) V8 проходить по всіх об'єктах, починаючи з **кореневих посилань (root set)** - змінних, доступних зі стека, глобальної області тощо. Усі об'єкти, до яких можна дістатися по посиланнях, позначаються як **"живі" (reachable)**. ### 2. Sweep (очищення) Після обходу непозначені об'єкти, що лишилися, вважаються **"сміттям"**, і пам'ять під них звільняється. Це гарантує, що будуть видалені тільки справді "мертві" об'єкти. ## 5. Дворівнева модель (Generational GC) Щоб підвищити ефективність, V8 ділить купу на покоління: ### Молоде покоління (Young Generation) - Містить недавно створені об'єкти. - Очищення відбувається **часто, але швидко** (Minor GC). - Алгоритм: **Scavenge (Copying GC)** - живі об'єкти копіюються з однієї половини пам'яті в іншу. Якщо об'єкт "виживає" кілька циклів GC → він **переміщується у старе покоління**. ### Старе покоління (Old Generation) - Зберігає довгоживучі об'єкти (наприклад, замикання, кеш, великі структури). - Очищення рідше, але складніше (Major GC). - Алгоритм: **Mark-Sweep / Mark-Compact**, з можливістю паралельної та інкрементальної обробки. ## 6. Сучасні оптимізації V8 GC V8 використовує **комбінацію GC-стратегій**, щоб мінімізувати "стоп-світ" (pause time): | Техніка | Призначення | |---|---| | Parallel GC | Частина GC виконується в кількох потоках | | Incremental GC | Ділить збирання сміття на маленькі кроки, щоб не блокувати Event Loop | | Concurrent Marking | Позначення об'єктів виконується паралельно з виконанням JS | | Compacting | Ущільнення пам'яті (щоб зменшити фрагментацію купи) | | Idle GC | GC може запускатися, коли Event Loop простоює | ## 7. Приклад візуально ```javascript function createUsers() { let users = []; for (let i = 0; i < 1_000_000; i++) { users.push({ id: i }); } return users; } createUsers(); // після завершення функції users більше не використовується → GC звільнить пам'ять ``` Після виходу з функції `createUsers()` масив `users` і всі його об'єкти **стають недосяжними**, і GC очистить їхню пам'ять під час наступного циклу. ## 8. Як GC впливає на продуктивність **Плюси:** - звільняє розробника від ручного керування пам'яттю; - запобігає витокам і переповненням. **Мінуси:** - може викликати *короткі паузи* ("stop-the-world"), коли GC зупиняє виконання JS; - якщо пам'ять сильно фрагментована або об'єктів дуже багато, GC може займати помітний час. Тому важливо писати **"GC-friendly" код**: - уникати зайвих глобальних змінних; - не зберігати великі структури в кеші без потреби; - "обнуляти" посилання на об'єкти, коли вони більше не потрібні. ## 9. GC не видаляє: - об'єкти, на які **все ще є посилання**; - **замикання**, якщо вони утримують контекст; - **взаємні посилання** (A → B і B → A) - поки хоча б одна доступна з кореня. Приклад витоку: ```javascript let cache = {}; function remember(key) { cache[key] = new Array(1e6).fill('*'); // зберігає посилання назавжди } ``` ## 10. Візуальна схема GC у V8 ```javascript ┌──────────────┐ │ Root Objects │ ← глобальні змінні, стек викликів └──────┬───────┘ ▼ ┌──────────────┐ │ Reachable │ ← позначені об'єкти │ (живі) │ └──────┬───────┘ ▼ ┌──────────────┐ │ Unreachable │ ← сміття → очищається └──────────────┘ ``` ## 11. Коротке резюме | Пункт | Опис | |---|---| | GC (Garbage Collection) | Автоматично звільняє пам'ять від "мертвих" об'єктів | | Алгоритм | Mark-and-Sweep + Generational GC | | Молоде покоління | Часто очищається, швидко | | Старе покоління | Рідко очищається, але складніше | | Оптимізації | Incremental, Concurrent, Parallel, Compacting | | Мета | Баланс між швидкістю й мінімальними паузами | | GC не врятує від витоків, якщо посилання зберігаються в коді | Не звільняє об'єкти, якщо на них є посилання |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.