Что такое ZGC?
4. Мониторьте Allocation Stall в логах 5. CPU overhead 5-15% — закладывайте при планировании
🟢 Junior Level
ZGC (Z Garbage Collector) — сборщик с минимальными паузами (< 1 мс), не зависящими от размера Heap. Throughput на 5-15% ниже, чем у G1.
Главное преимущество: Паузы практически не зависят от размера Heap и обычно < 1 мс. При экстремальной нагрузке возможны отклонения.
Когда использовать:
- Real-time системы
- High-frequency trading
- Когда SLA < 10 мс
🟡 Middle Level
Ключевые технологии
1. Colored Pointers:
64-битный указатель:
Биты 0-41: адрес объекта
Биты 42-45: метаданные (состояние GC)
→ GC понимает статус объекта, просто прочитав указатель
→ Без обращения к памяти объекта!
Colored Pointers — в 64-битных указателях ZGC использует верхние
биты для хранения метаданных (поколение, finalizable, weak и т.д.).
JVM «раскрашивает» указатели, экономя отдельную структуру данных.
2. Load Barriers:
При каждом чтении ссылки:
→ Проверить цвет указателя
→ Если объект переехал → исправить адрес (Self-healing)
→ overhead ~5-15% CPU
Load Barriers — проверки при КАЖДОМ чтении ссылки. Если указатель
«неправильный» (объект перемещён), Load Barrier автоматически
исправляет указатель (Self-Healing).
3. Concurrent Evacuation:
Объекты перемещаются БЕЗ остановки приложения!
→ В отличие от G1 (Evacuation = STW)
→ Пауза только для сканирования GC Roots
ZGC vs G1
| Критерий | G1 | ZGC |
|---|---|---|
| Пауза | 20-200 мс | < 1 мс |
| Throughput | Высокий | -5-10% |
| Max Heap | 64 ГБ | 16 ТБ |
| Barriers | Write | Load |
Generational ZGC (Java 21+)
До Java 21: одно поколение
→ Сканировал весь Heap при каждой сборке
До Java 21 ZGC был без поколений — это вызывало Allocation Stalls
при высоких allocation rate. Generational ZGC (Java 21+) решает
эту проблему.
Java 21+: Young и Old поколения
→ -50% CPU overhead
→ Allocation Stalls почти исчезли
Когда НЕ использовать
❌ CPU ограничен (90%+) → Load Barriers добьют
❌ Heap < 4 ГБ → G1 эффективнее
❌ 32-битные системы → ZGC требует 64-бит
Тюнинг
-XX:+UseZGC -XX:+ZGenerational # Java 21+
-XX:SoftMaxHeapSize=24g # Агрессивный возврат памяти
-XX:ConcGCThreads=4 # Потоки GC
🔴 Senior Level
Multi-mapping
Один физический участок памяти маппится на 3 виртуальных адреса
→ Разные комбинации бит метаданных
→ ОС не видит конфликта указателей
→ Позволяет работать с "цветными" указателями
Multi-mapping — техника отображения одной области Heap на несколько
виртуальных адресов, чтобы кодировать метаданные в адресах указателей.
Self-Healing Pointers
Load Barrier при чтении:
1. Прочитать указатель
2. Проверить бит Remapped
3. Если не Remapped → объект переехал
4. Вычислить новый адрес
5. Обновить указатель в Heap (CAS)
6. Вернуть новый адрес
→ Указатель "лечится" при каждом чтении
Allocation Stall Deep Dive
Причина: GC не успевает размечать мусор
→ Потоки приложения ждут освобождения памяти
Решения:
1. Увеличить Heap
2. Увеличить ConcGCThreads
`ConcGCThreads` по умолчанию = количество ядер / 4.
Увеличьте, если видите Allocation Stall; уменьшите, если GC забирает слишком много CPU.
3. Generational ZGC (Java 21+)
4. Уменьшить Allocation Rate
Best Practices
- Java 21+ — используйте Generational ZGC
- ConcGCThreads = количество ядер / 4
- SoftMaxHeapSize для контейнеров
- Мониторьте Allocation Stall в логах
- CPU overhead 5-15% — закладывайте при планировании
Резюме для Senior
- ZGC = Colored Pointers + Load Barriers + Conc Evacuation
- Паузы < 1 мс константны, не зависят от Heap
- Generational (Java 21+) = -50% overhead
- Self-healing указатели через Load Barriers
- Allocation Stall = главный риск
- CPU overhead 5-15% — цена за low latency
🎯 Шпаргалка для интервью
Обязательно знать:
- ZGC: паузы < 1 мс, не зависят от размера Heap (до 16 ТБ); throughput на 5-15% ниже G1
- Colored Pointers: верхние биты 64-битного указателя хранят метаданные (поколение, состояние GC)
- Load Barriers: при каждом чтении ссылки проверка цвета указателя + Self-healing (если объект переехал)
- Concurrent Evacuation: объекты перемещаются БЕЗ STW (в отличие от G1, где Evacuation = STW)
- Multi-mapping: один физический участок Heap маппится на 3 виртуальных адреса для кодирования метаданных
- Generational ZGC (Java 21+): разделение на Young/Old → -50% CPU overhead, Allocation Stalls почти исчезли
- Когда НЕ использовать: CPU bound (90%+), Heap < 4 ГБ, 32-битные системы
Частые уточняющие вопросы:
- Почему ZGC медленнее G1 по throughput? — Load Barriers при каждом чтении ссылки добавляют 5-15% CPU overhead
- Что такое Allocation Stall в ZGC? — GC не успевает размечать мусор → потоки приложения ждут; решения: увеличить Heap, ConcGCThreads, или Generational ZGC
- Что такое Self-Healing указатели? — Load Barrier читает указатель → проверяет бит Remapped → если объект переехал, вычисляет новый адрес и обновляет указатель (CAS)
- Зачем Multi-mapping? — Одна область Heap на 3 виртуальных адреса → кодирование метаданных в адресах без конфликта указателей
Красные флаги (НЕ говорить):
- «ZGC использует Write Barriers» — ZGC использует Load Barriers (при чтении); G1 использует Write Barriers (при записи)
- «ZGC работает на 32-битных системах» — ZGC требует 64-битную систему (Colored Pointers используют верхние биты)
- «ZGC всегда лучше G1» — для CPU-bound или batch processing G1 даёт лучший throughput
Связанные темы:
- [[12. Какие алгоритмы GC существуют]]
- [[13. Что такое G1 GC]]
- [[15. Что такое Shenandoah GC]]
- [[16. Что такое stop-the-world]]
- [[17. Какие GC минимизируют stop-the-world паузы]]