Питання 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)]]