Що таке GC roots?
4. Handshakes (Java 11+) → менше STW 5. Мінімізуйте кількість потоків
🟢 Junior Level
GC Roots — це «кореневі» об’єкти, від яких GC починає пошук живих об’єктів.
Проста аналогія: Дерево. Корені — це GC Roots. Якщо до гілки (об’єкта) можна дістатися від кореня → вона жива.
Що є GC Roots:
- Локальні змінні в методах
- Статичні поля класів
- Активні потоки
- JNI посилання
Правило: До об’єкта можна дістатися від GC Root → об’єкт живий.
🟡 Middle Level
Повна класифікація
GC Roots:
├── Stack Locals (локальні змінні)
├── Static Fields (статичні поля)
├── Thread Objects (активні потоки)
├── JNI Global (глобальні нативні посилання)
├── JNI Local (локальні нативні посилання)
├── Monitor Used (об'єкти в synchronized)
└── JVM Internal (системні об'єкти)
OopMaps
OopMaps (Ordinary Object Pointer Maps): JIT створює карту, де в кожному байті
коду вказано, які локальні змінні містять посилання. Без OopMaps GC
довелося б сканувати кожен байт стеку — повільно, плюс хибні спрацьовування
(звичайні int-значення, випадково схожі на вказівники).
→ У Safepoints JIT знає, які регістри/зміщення = посилання
→ Root Scanning за мілісекунди
Path to GC Roots (MAT)
MAT: Path to GC Roots
→ exclude soft/weak/phantom → тільки сильні посилання
→ Показує, хто тримає об'єкт
→ 99% витоків = сильні посилання від Static або Thread
🔴 Senior Level
Root Scanning і Latency
Кількість Roots впливає на паузи:
→ 1000 потоків → довге сканування стеків
→ Мільйони ключів у static HashMap
Modern Java (Handshakes):
→ Сканування потоків поодинці
→ Мінімізація глобальної паузи
JNI Global Reference витоки
Нативний код створив глобальне посилання:
→ NewGlobalRef(obj)
→ Забув DeleteGlobalRef
→ Об'єкт не видалиться GC!
→ «Невидима» витік
MAT показує JNI Global References як GC Roots. Вони відображаються як
"JNI Global" у Path to GC Roots view. Але JNI Local References (посилання
в native-коді) MAT не бачить — це «сліпа зона».
Finalizer Queue
Об'єкти з finalize():
→ Після смерті потрапляють у Finalizer Queue
→ Стають тимчасовим GC Root
→ Поки finalize() не виконається → об'єкт живий
→ Затримка видалення
→ Reference Handler потік обробляє чергу
Best Practices
- Моніторьте Root Scanning time у GC логах
- JNI → DeleteGlobalRef обов’язково
- exclude weak/soft у MAT
- Handshakes (Java 11+) → менше STW
- Мінімізуйте кількість потоків
Резюме для Senior
- GC Roots = фундамент Reachability Analysis
- OopMaps = швидке сканування
- JNI Global = невидимі витоки
- Root Scanning time → індикатор проблем
- Path to GC Roots = головний інструмент MAT
- Finalizer Queue = тимчасовий GC Root
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
- GC Roots — кореневі об’єкти, від яких GC починає обхід досяжності: Stack Locals, Static Fields, Thread Objects, JNI Global, JNI Local, Monitor Used, JVM Internal
- OopMaps: JIT створює карту, де в кожному байті коду вказано, які змінні містять посилання; без OopMaps GC сканував би кожен байт (повільно + хибні спрацьовування)
- Path to GC Roots (MAT): exclude soft/weak/phantom → тільки сильні посилання; 99% витоків = посилання від Static або Thread
- JNI Global Reference витоки:
NewGlobalRef(obj)безDeleteGlobalRef→ об’єкт не видалиться GC; MAT показує як «JNI Global» у Path to GC Roots - Finalizer Queue: об’єкти з
finalize()після смерті стають тимчасовим GC Root; покиfinalize()не виконається → об’єкт живий - Root Scanning time: кількість Roots впливає на паузи; 1000 потоків → довге сканування стеків; Handshakes (Java 11+) мінімізують глобальну паузу
Часті уточнюючі запитання:
- Чому OopMaps важливі для продуктивності? — Без OopMaps GC сканує кожен байт стеку → повільно + хибні спрацьовування (int, випадково схожий на вказівник)
- Як JNI Global Reference викликає витік? — Нативний код створив глобальне посилання і забув видалити; GC бачить його як GC Root → об’єкт ніколи не видалиться
- Чому Finalizer Queue — тимчасовий GC Root? — Об’єкт з
finalize()після смерті потрапляє у Finalizer Queue; покиfinalize()не виконається → об’єкт живий → затримка видалення - Що таке Root Scanning time у GC логах? — Час сканування всіх GC Roots; якщо росте → занадто багато потоків або статичних посилань
Червоні прапорці (НЕ говорити):
- «GC Roots — це тільки static поля» —还包括 Stack Locals, Thread Objects, JNI посилання, Monitor об’єкти
- «JNI витоки видно у Heap Dump» — JNI Global видно, але JNI Local (в native-коді) — «сліпа зона» MAT
- «finalize() швидкий і безпечний» — об’єкт живий, поки
finalize()не виконається; Reference Handler потік обробляє чергу асинхронно
Пов’язані теми:
- [[5. Коли об’єкт стає кандидатом на видалення GC]]
- [[26. Що таке reachability в контексті GC]]
- [[4. Що таке Garbage Collection]]
- [[21. Що таке витік пам’яті і як його виявити]]
- [[27. Чи можна вручну викликати GC]]