Skip to main content

Збирання сміття в V8

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 GCGC може запускатися, коли 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 не врятує від витоків, якщо посилання зберігаються в кодіНе звільняє об'єкти, якщо на них є посилання

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.