Вопрос 13 · Раздел 3

Что такое G1 GC?

G1 заменил Parallel GC как сборщик по умолчанию, потому что даёт предсказуемые паузы. Название «Garbage First» означает: сначала собираем регионы, где больше всего мусора (макси...

Версии по языкам: English Russian Ukrainian

🟢 Junior Level

G1 (Garbage First) — сборщик мусора по умолчанию в Java (с Java 9).

G1 заменил Parallel GC как сборщик по умолчанию, потому что даёт предсказуемые паузы. Название «Garbage First» означает: сначала собираем регионы, где больше всего мусора (максимальная эффективность за цикл).

Главная идея: Делит Heap на регионы и собирает в первую очередь самые “загрязнённые”.

Простая аналогия: Уборка в доме — сначала убираете самые грязные комнаты, а не весь дом сразу.

Преимущества:

  • Предсказуемые паузы (настраиваются)
  • Хорошо работает на Heap от 4 ГБ до десятков ГБ. Выше 32 ГБ отключаются Compressed OOPs — это влияет на все GC, не только G1.
  • Баланс между скоростью и паузами

🟡 Middle Level

Регионы G1

Heap разбит на 2048 регионов (1-32 МБ каждый)

Типы регионов:
  Eden — новые объекты
  Survivor — выжившие
  Old — долгоживущие
  Humongous — большие объекты (> 50% региона)
  Free — свободные

Remembered Sets (RSet)

Каждый регион хранит: какие ДРУГИЕ регионы на него ссылаются

Зачем:
  → При Young GC не нужно сканировать весь Old Gen
  → Сканируются только регионы с ссылками на Young

Remembered Sets (RSet) — структура данных для каждого региона,
которая отслеживает входящие ссылки из ДРУГИХ регионов.
Позволяет G1 не сканировать весь Heap.

Цикл работы

1. Young GC (STW) — копирование молодых объектов
2. Concurrent Marking — фоновая разметка Old Gen
3. Mixed GC — Young + самые грязные регионы Old

Цель: уложиться в MaxGCPauseMillis

Тюнинг

-XX:MaxGCPauseMillis=200     # Целевая пауза
-XX:InitiatingHeapOccupancyPercent=45  # Порог Old GC

🔴 Senior Level

Collection Set (CSet)

Набор регионов для очистки в текущем цикле

Collection Set (CSet) — набор регионов, выбранных для сборки
в текущем цикле. G1 выбирает регионы с наибольшим количеством мусора.

Young GC:
  → CSet = все Young регионы
  
Mixed GC:
  → CSet = Young + самые грязные Old регионы
  → G1 выбирает, чтобы уложиться в MaxGCPauseMillis

Evacuation Failure

При копировании живых объектов нет места в целевых регионах
  → To-space exhausted
  → Full GC (STW!)

Evacuation Failure (To-space exhausted) — когда G1 не хватает
места для копирования живых объектов. Fallback к Full GC —
долгая пауза.

Причины:
  - Фрагментация
  - Слишком много живых объектов
  
Решение: увеличить Heap или уменьшить MaxGCPauseMillis

String Deduplication

-XX:+UseStringDeduplication

G1 находит одинаковые char[] в разных String
  → Схлопывает в одну ссылку
  → Экономия 5-10% Heap

Работает только для String, созданных через new String() или конкатенацию.
Строки из пула литералов уже дедуплицированы. Наибольший эффект для
приложений с большим количеством одинаковых строк.

Generational ZGC vs G1

G1: паузы 20-200 мс, хороший throughput
ZGC: паузы < 1 мс, -5-10% throughput

Выбор: SLA < 10 мс → ZGC, иначе G1

Generational ZGC требует Java 21+. На Java 17 используйте G1.

Best Practices

  1. Не фиксируйте -Xmn для G1 (теряет адаптивность)
  2. MaxGCPauseMillis не ставьте слишком низко (< 50 мс)
  3. IHOP настройте под ваш Promotion Rate
  4. Humongous → увеличьте G1HeapRegionSize
  5. String Deduplication включите для экономии памяти
  6. Мониторьте To-space exhausted

Резюме для Senior

  • G1 = региональный, адаптивный GC
  • RSet = оптимизация Young GC
  • CSet = выбирает самые грязные регионы
  • SATB = concurrent marking алгоритм
  • Evacuation Failure = худший сценарий
  • Не фиксируйте Young Gen — G1 адаптивен
  • MaxGCPauseMillis = главный рычаг настройки

🎯 Шпаргалка для интервью

Обязательно знать:

  • G1 делит Heap на 2048 регионов (1-32 МБ); типы: Eden, Survivor, Old, Humongous, Free
  • RSet (Remembered Set): каждый регион хранит, какие другие регионы на него ссылаются → Young GC не сканирует весь Heap
  • CSet (Collection Set): регионы, выбранные для сборки в текущем цикле; G1 выбирает самые «грязные»
  • Цикл G1: Young GC (STW) → Concurrent Marking → Mixed GC (Young + грязные Old регионы)
  • Evacuation Failure (To-space exhausted): нет места для копирования живых → Full GC (STW!)
  • SATB (Snapshot-At-The-Beginning): concurrent marking; Floating Garbage — объекты, ставшие мусором после snapshot
  • String Deduplication (-XX:+UseStringDeduplication): G1 схлопывает одинаковые char[] в String → экономия 5-10% Heap

Частые уточняющие вопросы:

  • Почему нельзя ставить MaxGCPauseMillis слишком низко (< 50 мс)? — G1 не сможет уложиться → Evacuation Failure → Full GC
  • Что такое IHOP (InitiatingHeapOccupancyPercent)? — Порог Old Gen (по умолчанию 45%), при котором G1 начинает Concurrent Marking; настройте под ваш Promotion Rate
  • Что делать с Humongous Objects? — Увеличьте -XX:G1HeapRegionSize (например, 16м или 32м), чтобы объекты не считались Humongous
  • Почему не фиксируется -Xmn для G1? — G1 адаптивно меняет Young Gen для достижения MaxGCPauseMillis; фиксация ломает адаптивность

Красные флаги (НЕ говорить):

  • «G1 сканирует весь Old Gen при Young GC» — RSet оптимизация: сканируются только регионы с ссылками на Young
  • «Поставлю MaxGCPauseMillis=10 мс для максимальной скорости» — G1 не сможет уложиться → To-space exhausted → Full GC
  • «String Deduplication экономит память на строках из String Pool» — работает только для new String() и конкатенации; строки из пула уже дедуплицированы

Связанные темы:

  • [[8. Что такое поколения в GC (young, old, metaspace)]]
  • [[12. Какие алгоритмы GC существуют]]
  • [[14. Что такое ZGC]]
  • [[16. Что такое stop-the-world]]
  • [[10. Что такое Old Generation (Tenured)]]