Что такое Old Generation (Tenured)
Для очистки старшего поколения применяются два классических подхода:
🟢 Junior Level
Old Generation (Старшее поколение, Tenured) — это область кучи (Java Heap), предназначенная для хранения долгоживущих объектов, которые успешно пережили несколько циклов сборок мусора в Young Generation либо были размещены здесь напрямую из-за своего большого размера.
Основные характеристики Old Generation:
- Размер: Занимает подавляющую часть кучи (по умолчанию при
-XX:NewRatio=2на Old Gen приходится $2/3$ всей памяти Heap). - Паттерн объектов: Объекты здесь стабильны и умирают крайне медленно (синглтоны Spring, пулы соединений HikariCP, долгоживущие кэши, сессии пользователей).
- Стоимость сборки: Сборка мусора в Old Generation требует значительно больше времени и ресурсов CPU, чем в Young Generation, так как сканируется огромный массив данных.
Как объекты попадают в Old Generation:
- Естественное взросление (Tenuring): Объект пережил в Young Gen заданное количество сборок Minor GC (по умолчанию до 15 циклов).
- Переполнение Survivor (Survivor Overflow): Объем выживших после Minor GC объектов превысил емкость региона Survivor, и излишки были вытолкнуты в Old Gen.
- Крупные объекты (Humongous Objects): Массивы, размер которых превышает половину региона в G1 GC, аллоцируются в Old Gen напрямую, минуя Eden.
🟡 Middle Level
Алгоритмы очистки: Mark-Sweep vs Mark-Compact
Для очистки старшего поколения применяются два классических подхода:
| Алгоритм | Описание работы | Плюсы | Минусы |
|---|---|---|---|
| Mark-Sweep | 1. Разметка живых объектов. 2. Очистка мертвых, добавление их координат в списки свободных блоков (Free Lists). |
Высокая скорость, возможность фонового выполнения | Фрагментация памяти: куча превращается в «швейцарский сыр» с множеством разрозненных дыр. |
| Mark-Compact | 1. Разметка живых объектов. 2. Сдвиг всех выживших объектов в начало памяти единым блоком (уплотнение). |
Нулевая фрагментация: восстанавливает быстрый bump-the-pointer | Долгие паузы Stop-The-World (требуется несколько проходов для обновления всех ссылок). |
Авария производительности: Promotion Failure
Promotion Failure (Сбой продвижения) — критическая ситуация при выполнении Minor GC:
- Сборщик мусора пытается переместить выживший объект из Survivor в Old Generation.
- В Old Generation нет непрерывного куска памяти нужного размера (из-за фрагментации или исчерпания объема).
- Последствие: JVM экстренно останавливает все потоки приложения и запускает аварийный Full GC (Mark-Compact по всей куче), замораживая сервис на секунды или десятки секунд.
Очистка Old Gen в G1: Механика Mixed GC и параметр IHOP
В отличие от старых сборщиков, G1 не пытается очистить весь Old Gen разом в рамках одной гигантской паузы:
Куча G1:
[Young] [Young] [Old-1] [Old-2] [Old-3] [Free] ...
│
▼
Выбираются только регионы Old с максимальным % мусора ("Garbage-First")
- IHOP (Initiating Heap Occupancy Percent):
- Порог заполнения кучи, при котором запускается фоновая фаза разметки Old Gen (по умолчанию 45%).
- В современном JDK по умолчанию включен адаптивный расчет
-XX:+G1UseAdaptiveIHOP: JVM сама замеряет скорость заполнения Old Gen и время разметки, динамически сдвигая порог старта, чтобы сборщик успел разметить память до ее исчерпания.
- Mixed GC (Смешанная сборка):
- G1 собирает все регионы Young Gen плюс несколько самых «грязных» регионов Old Gen (где мусора больше всего).
- Очистка Old Gen происходит инкрементально порциями за несколько циклов (
-XX:G1MixedGCCountTarget=8), укладываясь в целевое окно паузы (-XX:MaxGCPauseMillis=200).
🔴 Senior Level
Плавающий мусор (Floating Garbage)
При конкурентной разметке (Concurrent Marking в G1, ZGC, Shenandoah) приложение продолжает выполняться параллельно со сборщиком мусора:
- Если во время разметки поток приложения обнуляет ссылку
myObj = null;, объектmyObjуже был помечен сборщиком как «живой» на момент снимка SATB (Snapshot-At-The-Beginning). - Этот объект фактически стал мертвым, но сборщик не удалит его в текущем цикле.
- Такой мусор называется Floating Garbage (Плавающий мусор). Он неизбежно занимает память до следующего цикла GC. При расчете сайзинга кучи всегда закладывают 20–30% резерва под плавающий мусор.
Конкурентное уплотнение в ZGC и Shenandoah
В традиционных сборщиках перемещение долгоживущих объектов в Old Gen требовало полной остановки приложения (STW), поскольку перемещение объекта меняет его физический адрес в памяти.
В современных low-latency сборщиках уплотнение Old Gen переведено в конкурентный режим:
- ZGC: Использует Colored Pointers (биты ссылки указывают статус объекта) и Load Barriers на чтение. Если поток читает объект из Old Gen, который находится в процессе перемещения, Load Barrier сам перенаправляет вызов на новый адрес и обновляет указатель на лету.
- Shenandoah: Использует указатели Брукса (Brooks Pointers) или LRB (Load-Reference Barriers) для прозрачной переадресации потоков к новой копии объекта в процессе эвакуации.
Мониторинг и диагностика в логах
Признаки проблем со старшим поколением в логах -Xlog:gc*:
[GC(45) Pause Young (Normal) (G1 Evacuation Pause) 1800M->1800M(2048M) ... (to-space exhausted)]
[GC(46) Pause Full (System.gc()) 1800M->400M(2048M) 2150.320ms]
to-space exhausted— сигнал о нехватке места для продвижения объектов в Old Gen.Pause Fullдлительностью 2150 мс — катастрофический Stop-The-World, означающий, что G1 не справился инкрементально и свалился в глобальный Full GC.
🎯 Шпаргалка для интервью
30-секундный ответ (Elevator Pitch)
«Old Generation (Tenured) — это область кучи, где размещаются долгоживущие объекты (пережившие
MaxTenuringThresholdв Young Gen) и крупные массивы (Humongous в G1). Сборка здесь дороже, чем в Young Gen. В классических сборщиках она выполняется через Mark-Sweep-Compact, а в G1 — инкрементально через фазы Concurrent Marking и Mixed GC, стартующие по порогу IHOP (по умолчанию 45%). Главные производственные риски Old Gen — Promotion Failure (когда объекты из Young не могут поместиться в Old из-за фрагментации, вызывая Full GC) и накопление Floating Garbage (плавающего мусора) при параллельной разметке».
3–4 каверзных вопроса с ответами
- Что такое Promotion Failure и почему это катастрофа для задержек (Latency) сервиса?
- Ответ: Promotion Failure возникает при Minor GC, когда выжившие объекты из Eden/Survivor не могут быть скопированы в Old Generation из-за отсутствия непрерывного свободного блока памяти (вызванного сильной фрагментацией или переполнением Old Gen). В этот момент JVM не может продолжить работу и инициирует аварийный однопоточный или параллельный Full GC со Stop-The-World паузой на всю кучу, что приводит к замиранию сервиса на секунды.
- В чем разница между Major GC, Mixed GC и Full GC?
- Ответ:
- Major GC: Очистка строго старшего поколения (Old Generation).
- Mixed GC (в сборщике G1): Очищает целиком всё Young Generation плюс несколько выбранных наиболее загрязненных регионов Old Generation.
- Full GC: Глобальная сборка всей виртуальной машины целиком: очищается Young Gen, Old Gen и выгружаются неиспользуемые классы из Metaspace. Сопровождается тяжелейшей паузой STW.
- Ответ:
- Что такое параметр IHOP в G1 GC и как работает Adaptive IHOP?
- Ответ: IHOP (Initiating Heap Occupancy Percent) — это порог заполнения кучи (по умолчанию 45%), при превышении которого G1 инициирует фоновый цикл конкурентной разметки Old Generation. Начиная с Java 9, включен адаптивный режим: JVM постоянно замеряет скорость аллокации (Allocation Rate) и фактическую длительность цикла разметки, динамически подстраивая порог так, чтобы разметка завершалась ровно перед тем, как память Old Gen исчерпается.
- Что такое «Плавающий мусор» (Floating Garbage)?
- Ответ: Это объекты, которые стали недостижимыми (потеряли ссылки) уже после того, как сборщик мусора сделал снимок графа объектов в начале фазы конкурентной разметки (SATB). Сборщик считает их живыми до конца текущего цикла, поэтому они не могут быть собраны прямо сейчас и продолжают временно занимать память до следующего цикла GC.
Типичные ошибки и Red Flags
- 🚩 Утверждение: «Full GC в production — это нормальное явление» (в современных системах с настроенным G1 или ZGC Full GC свидетельствует об ошибке сайзинга, утечке памяти или нехватке ресурсов).
- 🚩 Попытка лечить Promotion Failure простым раздуванием Heap без устранения генерации мусора или настройки регионов.
- 🚩 Игнорирование плавающего мусора (Floating Garbage) при расчете запаса памяти под highload-нагрузки.
- 🚩 Путаница между терминами Minor GC, Mixed GC и Full GC.
Связанные темы
- Что такое поколения в GC — общая архитектура поколений памяти
- Что такое Young Generation — источник объектов для Old Generation
- Что такое G1 GC — детали работы Mixed GC и IHOP
- Что такое ZGC — сборщик со сверхнизкими паузами
- Что такое stop-the-world — природа глобальных пауз при Full GC