Чому не варто викликати System.gc()?
4. Не ловіть OOME через System.gc() 5. Шукайте витік, а не «допомагайте» GC
🟢 Junior Level
System.gc() — погана практика, тому що:
- Зупиняє додаток — всі потоки чекають
- GC розумніший за вас — сам знає, коли прибрати
- Тратить CPU — часто без користі
// ❌ Не робіть так!
System.gc(); // «Допомагаю» GC
// ✅ Довіртеся JVM
// GC сам вирішить, коли потрібно
🟡 Middle Level
Руйнування адаптивних моделей
Сучасні GC (G1, ZGC) само-навчаються:
→ Allocation Rate
→ Promotion Rate
→ Pause Time Goals
System.gc() = зовнішній шок:
→ Скидає статистику
→ GC вчиться заново
→ Непередбачувані паузи
Concurrent Mode Failure
Concurrent Mode Failure (G1) — concurrent marking не встиг завершити,
Old Gen заповнився → fallback до Full GC. Це найдовша пауза в G1.
System.gc() може спровокувати цей сценарій, якщо викликаний у непідходящий момент.
Як знайти винуватця
# 1. GC Logs
-Xlog:gc*
# → "Pause Full (System.gc())"
# 2. JFR
# → Подія "System GC"
# → Повний стек-трейс
# 3. Рішення
-XX:+ExplicitGCInvokedConcurrent # Конкурентно
# або
-XX:+DisableExplicitGC # Ігнорувати
🔴 Senior Level
Деоптимізація JIT
Full GC → class unloading → деоптимізація гарячих методів.
Code Cache очищується окремо (CodeCache sweeper).
→ Після GC: інтерпретація коду
→ Throughput падає на секунди
→ «Кувалда для швейцарського годинника» — System.gc() грубо зупиняє
всі оптимізації JVM ради примусового збирання сміття.
GC Thrashing
Спроба «полікувати» OOM через System.gc():
→ Звільняє крихти пам'яті
→ Тратить 95% CPU на GC
→ Маскує реальну проблему
→ Краще нехай впаде і перезапуститься
Production: DisableExplicitGC
-XX:+DisableExplicitGC
# → Ігнорує всі виклики System.gc()
# → Крім Direct Buffers (обережно!)
# Альтернатива:
-XX:+ExplicitGCInvokedConcurrent
# → Конкурентний GC замість Full GC STW
Best Practices
- Єдиний легітимний кейс — бенчмарки (JMH)
- JFR для пошуку того, хто викликає
- ExplicitGCInvokedConcurrent для production
- Не ловіть OOME через System.gc()
- Шукайте витік, а не «допомагайте» GC
Резюме для Senior
- System.gc() = «кувалда для швейцарського годинника» — грубо зупиняє всі оптимізації JVM
- Руйнує адаптивні моделі GC
- Concurrent Mode Failure → Full GC STW
- JIT деоптимізація → втрата Throughput
- JFR = знайти того, хто викликає
- DisableExplicitGC або ExplicitGCInvokedConcurrent
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
- System.gc() — антипатерн: Full GC = STW (секунди), скидає адаптивну статистику GC, JIT деоптимізація гарячих методів
- G1/ZGC само-навчаються (Allocation Rate, Promotion Rate, Pause Time Goals); System.gc() = зовнішній шок → GC вчиться заново
- Concurrent Mode Failure (G1): concurrent marking не встиг → Old Gen заповнений → Full GC STW; System.gc() може спровокувати
- JIT деоптимізація: Full GC → class unloading → гарячі методи → інтерпретація → throughput падає на секунди
- GC Thrashing: спроба «полікувати» OOM через System.gc() → 95% CPU на GC → маскує реальну проблему
- Production:
-XX:+ExplicitGCInvokedConcurrent(конкурентний GC замість STW) або-XX:+DisableExplicitGC(ігнорувати, обережно з Direct Buffers!) - Єдиний легітимний кейс — бенчмарки (JMH)
Часті уточнюючі запитання:
- Чому System.gc() руйнує адаптивні моделі? — G1/ZGC накопичують статистику (allocation rate, promotion rate); System.gc() = раптовий Full GC → статистика скинута → GC «забуває» поведінку додатку
- Що таке Concurrent Mode Failure? — G1 concurrent marking не встиг завершити до заповнення Old Gen → fallback до Full GC (найдовша пауза в G1)
- Як знайти, хто викликає System.gc()? —
-Xlog:gc*(шукайте “Pause Full (System.gc())”); JFR (подія “System GC” з повним стек-трейсом) - Чому JIT деоптимізація відбувається? — Full GC → class unloading → JIT-скомпільовані методи видалені → перекомпіляція заново
Червоні прапорці (НЕ говорити):
- «Викликаю System.gc() для профілактики» — GC сам знає; ручний виклик = STW + руйнування адаптивних моделей
- «Ловлю OOME і викликаю System.gc()» — GC Thrashing: 95% CPU на GC; краще fail-fast і перезапуск
- «System.gc() покращує продуктивність» — «кувалда для швейцарського годинника»; грубо зупиняє всі оптимізації JVM
Пов’язані теми:
- [[27. Чи можна вручну викликати GC]]
- [[4. Що таке Garbage Collection]]
- [[13. Що таке G1 GC]]
- [[19. Що станеться при OutOfMemoryError]]
- [[16. Що таке stop-the-world]]