Що таке stop-the-world?
JVM використовує polling page (сторінку пам'яті) замість прапорцевого check, тому що читання з кешу (сторінка майже завжди в L1) швидше, ніж галуження (branch). Це «fast path» —...
🟢 Junior Level
Stop-The-World (STW) — це коли JVM зупиняє всі потоки додатку для виконання GC.
Проста аналогія: Уявіть, що ви працюєте в офісі, і раптом оголошують евакуацію. Всі зупиняються і чекають, поки перевірка закінчиться.
Навіщо потрібен STW:
- GC — потрібне консистентне становище пам’яті (об’єкти не переміщуються під час обходу)
- Не-GC операції: thread dumps, biased lock revocation, class redefinition (JVM TI)
Як довго:
- ZGC: < 1 мс
- G1: 20-200 мс
- Full GC: секунди
🟡 Middle Level
Safepoints
Потоки не можуть зупинитися миттєво!
→ Повинні дійти до Safepoint (точки зупинки)
Де розставлені:
- Перед виходом з методу
- В кінцях циклів
- Перед викликами методів
Механізм: Safepoint Poll
→ JVM позначає сторінку як недоступну
→ Потік читає → SIGSEGV → переходить в очікування
TTSP (Time To Safepoint)
Час від команди «стоп» до останнього зупиненого потоку
Проблеми:
- Counted Loops (цикли int) → можуть не мати Safepoints
- Масивний I/O → потік у системному виклику
- Свопінг → сторінка Safepoint у swap
Рішення: -XX:+UseCountedLoopSafepoints
Thread-Local Handshakes (Java 11+)
Раніше: зупинити ВСІ потоки для операції над одним
Тепер: Handshake з конкретним потоком
→ Решта працюють!
→ Приклади: Thread Dump, Biased Lock відкликання
Діагностика
# Логи Safepoints
-Xlog:safepoint
-Xlog:safepoint+stats
# Шукайте:
# "reaching safepoint" → час очікування
# Якщо > 100 мс → проблема!
🔴 Senior Level
Safepoint Polling Mechanics
Safepoint Page:
Normal: сторінка доступна → читання миттєво
STW: Guard Page → SIGSEGV → потік в очікуванні
JIT вставляє перевірку в кожен Safepoint:
movl r0, [safepoint_page] // Fast Path
→ Якщо сторінка недоступна → trap
JVM використовує polling page (сторінку пам’яті) замість прапорцевого check, тому що читання з кешу (сторінка майже завжди в L1) швидше, ніж галуження (branch). Це «fast path» — майже нульовий overhead.
Counted Loops Problem
// ❌ JIT не вставляє Safepoints у counted loops
for (int i = 0; i < 1_000_000_000; i++) {
// Мільярд ітерацій без перевірки!
// GC чекає → TTSP = секунди
}
// Рішення:
-XX:+UseCountedLoopSafepoints
// → JIT вставляє перевірки кожні N ітерацій
// → overhead ~1-2%
JNI і STW
JNI-потоки: JVM не може інспектувати їх стек під час STW.
JVM чекає, поки JNI-потік повернеться в Java-код (досягне safepoint).
JNI-потік не «працює під час STW» — він заблокований при спробі повернутися в Java.
JFR Safepoint Events
Java Flight Recorder:
→ Подія 'Safepoint Begin'
→ Час: entering + waiting + cleanup
→ Візуалізація в JMC
Пошук проблем:
→ Якщо entering > 50 мс → проблема з TTSP
→ Якщо waiting > entering → один потік гальмує
Best Practices
- Моніторьте TTSP через логи safepoint
- Counted Loops → UseCountedLoopSafepoints
- Handshakes (Java 11+) → менше STW
- JFR для візуалізації
- Уникайте довгих циклів без Safepoints
- JNI → стежте за часом у native
Резюме для Senior
- STW = не тільки GC, але й інші операції JVM
- Safepoints = механізм координації потоків
- TTSP = час входу в STW (може бути > самого GC!)
- Counted Loops = часта причина довгих TTSP
- Handshakes (Java 11+) = зниження глобальних пауз
- JFR = найкращий інструмент для аналізу
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
- STW — JVM зупиняє ВСІ потоки додатку; не тільки для GC, але й для thread dumps, biased lock revocation, class redefinition
- Safepoints — точки в коді (вихід з методу, кінець циклу), де потік може зупинитися; механізм: Safepoint Poll (Guard Page → SIGSEGV)
- TTSP (Time To Safepoint) — час від команди «стоп» до останнього зупиненого потоку; може бути довшим за сам GC!
- Counted Loops — JIT не вставляє Safepoints у цикли
for (int i...)→ TTSP = секунди; рішення:-XX:+UseCountedLoopSafepoints - Thread-Local Handshakes (Java 11+) — операція з конкретним потоком без зупинки всіх решти
- JNI-потоки: JVM чекає, поки JNI-потік повернеться в Java-код; потік НЕ працює під час STW, він заблокований при спробі повернутися
- Polling page — читання з кешу (сторінка майже завжди в L1) швидше branch; fast path = майже 0 overhead
Часті уточнюючі запитання:
- Чому TTSP може бути довшим за сам GC? — Counted Loops без Safepoints, масивний I/O (потік у системному виклику), свопінг сторінки Safepoint
- Як діагностувати довгі TTSP? —
-Xlog:safepoint(шукайте “reaching safepoint” > 100 мс); JFR: подія Safepoint Begin → entering/waiting/cleanup - Що таке Thread-Local Handshakes? — Java 11+: handshake з конкретним потоком замість зупинки всіх; приклади: Thread Dump, Biased Lock відкликання
- Чому Safepoint Polling швидше за прапорцевий check? — Читання з кешу L1 (сторінка майже завжди там) швидше branch; fast path = майже 0 overhead
Червоні прапорці (НЕ говорити):
- «STW потрібен тільки для GC» — STW також для thread dumps, biased lock revocation, class redefinition
- «JNI-потоки працюють під час STW» — JNI-потік заблокований при спробі повернутися в Java; JVM чекає його
- «Counted Loops не впливають на продуктивність» — без Safepoints TTSP може бути секунди
Пов’язані теми:
- [[4. Що таке Garbage Collection]]
- [[17. Які GC мінімізують stop-the-world паузи]]
- [[14. Що таке ZGC]]
- [[13. Що таке G1 GC]]
- [[12. Які алгоритми GC існують]]