Збирання сміття в V8
1. Що таке збирання сміття
Garbage Collection (збирання сміття) - це процес автоматичного звільнення пам'яті, яку займають об'єкти, що більше не використовуються в програмі.
Ідея:
Якщо на об'єкт немає посилань, його можна безпечно видалити з пам'яті.
Приклад:
let user = { name: 'Tim' };
user = null; // тепер на об'єкт немає посилань → GC звільнить пам'ять2. Як керується пам'ять у V8
Коли ти створюєш об'єкт, масив, функцію чи рядок, V8 виділяє під них пам'ять у купі (heap). V8 ділить купу на дві частини:
- New Space (молоде покоління) - для недавно створених об'єктів;
- 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. Приклад візуально
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) - поки хоча б одна доступна з кореня.
Приклад витоку:
let cache = {};
function remember(key) {
cache[key] = new Array(1e6).fill('*'); // зберігає посилання назавжди
}10. Візуальна схема GC у V8
┌──────────────┐
│ Root Objects │ ← глобальні змінні, стек викликів
└──────┬───────┘
▼
┌──────────────┐
│ Reachable │ ← позначені об'єкти
│ (живі) │
└──────┬───────┘
▼
┌──────────────┐
│ Unreachable │ ← сміття → очищається
└──────────────┘11. Коротке резюме
| Пункт | Опис |
|---|---|
| GC (Garbage Collection) | Автоматично звільняє пам'ять від "мертвих" об'єктів |
| Алгоритм | Mark-and-Sweep + Generational GC |
| Молоде покоління | Часто очищається, швидко |
| Старе покоління | Рідко очищається, але складніше |
| Оптимізації | Incremental, Concurrent, Parallel, Compacting |
| Мета | Баланс між швидкістю й мінімальними паузами |
| GC не врятує від витоків, якщо посилання зберігаються в коді | Не звільняє об'єкти, якщо на них є посилання |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.