Сначала измерить
Тюнинг GC начинается не с подбора флагов, а с фактов: какие паузы (средние и хвостовые p99), какой throughput, как часто и почему происходят сборки, растёт ли потребление со временем. Менять флаги вслепую обычно делает хуже.
Главное правило: сначала цель (например, p99 паузы < 50 мс при заданном RPS), потом измерение, потом изменение одного параметра и повторный замер.
Ключевые флаги
Базовое: -Xms/-Xmx (начальный/максимальный размер кучи; часто их делают равными, чтобы избежать дорогих изменений размера). Выбор сборщика: -XX:+UseG1GC (обычно дефолт), -XX:+UseZGC для сверхнизких пауз. Для G1 цель пауз задаётся -XX:MaxGCPauseMillis.
Размеры поколений и Survivor (-XX:NewRatio, -XX:SurvivorRatio, -XX:MaxTenuringThreshold) трогают точечно и только по данным — чаще достаточно дать сборщику цель пауз и адекватную кучу.
GC-логи и метрики
С Java 9 включён unified logging: -Xlog:gc* пишет причины сборок, паузы, размеры поколений до/после. Это первичный источник правды о поведении GC.
Ключевые метрики: длительность и частота пауз, throughput (доля времени вне GC), allocation rate (сколько МБ/с создаётся — высокий разгоняет minor GC), promotion rate (сколько уезжает в old — высокий ведёт к full GC). Их снимают из логов или через JFR/JMX.
# Логи в файл с ротацией — то, что включают на проде по умолчанию
java -Xlog:gc*,safepoint:file=gc.log:time,uptime,level:filecount=5,filesize=20M \
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/app \
-Xms4g -Xmx4g -jar app.jar
# Строка о полной сборке читается так:
[42.117s][info][gc] GC(37) Pause Full (G1 Compaction Pause) 3894M->3702M(4096M) 812.443ms
# ^^^^^ ^^^^^
# после Full освободилось всего 192M при куче 4G — живой набор почти равен куче:
# это утечка или недостаточная куча, флагами сборщика такое не лечится.
Типичные проблемы
Частые full GC: обычно утечка, premature promotion (мал Survivor) или просто мала куча — смотрят, растёт ли old после каждого цикла. Высокий allocation rate: чрезмерное создание временных объектов — лечится не флагами, а кодом (переиспользование, примитивы, потоки данных).
Длинные паузы при большой куче: повод перейти на ZGC. OutOfMemoryError: снять heap dump (-XX:+HeapDumpOnOutOfMemoryError) и искать доминаторы.
Как отвечать на собеседовании
Покажите дисциплину «цель → измерение → один параметр → замер», назовите базовые флаги (-Xms/-Xmx, выбор сборщика, цель пауз для G1), источники данных (unified -Xlog:gc, JFR) и ключевые метрики (паузы, throughput, allocation/promotion rate). Свяжите частые full GC с утечкой/premature promotion, а не с «надо больше памяти».