ZGC или Z Garbage Collector это сборщик мусора с малой задержкой, встроенный в JDK. Первоначально он появился в JDK 11 в виде экспериментальной функции. Продакшн-функцией ZGC стал в JDK 15 после утверждения улучшения JEP 377. С тех пор он сильно изменился: с JDK 21 у ZGC появился поколенческий режим, с JDK 23 он работает так по умолчанию, а с JDK 24 другого режима у него просто нет.
В этой статье мы рассмотрим цели и перспективы ZGC.
![Человек несет пакеты с мусором к переполненному контейнеру на заснеженной парковке, заставка к статье о сборщике мусора]()
Кратко
- ZGC это сборщик мусора, который экономит не процессор, а время отклика: паузы приложения он держит в пределах миллисекунды.
- Длительность пауз не зависит от размера кучи, поэтому ZGC одинаково ведет себя и на сотнях мегабайт, и на терабайтах.
- Платить за это приходится пропускной способностью: она примерно на 10 процентов ниже, чем у G1.
- По умолчанию в JDK до сих пор работает G1, ZGC включают флагом
-XX:+UseZGC.
- Главная настройка это максимальный размер кучи
-Xmx, остальное ZGC подбирает сам.
- С JDK 24 ZGC существует только в поколенческом варианте: старый режим и флаг
-XX:+ZGenerational удалены из языка.
Обзор ZGC
ZGC разработан как масштабируемый сборщик мусора с малой задержкой. Максимальное время паузы при работе ZGC редко превышает 250 микросекунд, Да, именно микросекунд, со средним временем паузы в десятки микросекунд.
ZGC обладает высокой масштабируемостью: по документации Oracle он хорошо работает с кучей от нескольких сотен мегабайт до 16 ТБ. Важно отметить, что время паузы не увеличивается с размером кучи. Таким образом, даже с кучей размером в несколько терабайт время паузы все равно будет измеряться в микросекундах.
Хотя ZGC обеспечивает малую задержку и высокую масштабируемость, это происходит за счет пропускной способности, которая примерно на 10% ниже по сравнению с G1. Конкретное снижение пропускной способности зависит от дизайна приложения, архитектуры системы и потребностей бизнеса.
Использование ZGC
Поскольку начиная с JDK 9
сборщиком мусора по умолчанию назначен G1, для использования ZGC вам потребуется установка флага VM -XX:+UseZGC.
При использовании ZGC наиболее важной конфигурацией является установка максимального размера кучи, -Xmx. Размер кучи должен быть достаточно большим, чтобы справляться с live-set вашего приложения. Также он должен иметь дополнительный резерв для выполнения сборки мусора. Чем больше доступного места в куче, тем реже потребуется выполнять сборку мусора. Но учтите, что это должно быть сбалансировано с использованием памяти.
Дальнейшее развитие ZGC
С момента своего выпуска в качестве производственной функции в JDK 15 ZGC продолжает активно развиваться, и главное изменение уже произошло: сборщик стал поколенческим, то есть разделяет молодые и старые объекты и обходит их по-разному. Вот как выглядит путь ZGC по версиям JDK:
| Версия |
Что изменилось |
Источник |
| JDK 11 |
ZGC появился как экспериментальная функция |
JEP 333 |
| JDK 15 |
ZGC стал продакшн-функцией |
JEP 377 |
| JDK 16 |
параллельная обработка стека потоков |
JEP 376 |
| JDK 18 |
добавлена дедупликация строк |
|
| JDK 21 |
появился поколенческий ZGC, пока как дополнительный режим |
JEP 439 |
| JDK 23 |
поколенческий режим включен по умолчанию |
JEP 474 |
| JDK 24 |
непоколенческий режим удален вместе с флагом -XX:+ZGenerational |
JEP 490 |
Так что фраза «ZGC когда-нибудь станет поколенческим», которую можно встретить в статьях 2022 года, устарела: в документации Oracle прямо сказано, что начиная с JDK 24 ZGC это поколенческий сборщик, а опция
ZGenerational удалена.
Дополнительная информация о ZGC
Вопросы и ответы
Что такое ZGC и зачем он нужен?
Это сборщик мусора в JDK, рассчитанный на малую задержку. Его задача не в том, чтобы собрать мусор быстрее всех, а в том, чтобы как можно меньше останавливать приложение: паузы измеряются долями миллисекунды и не растут вместе с кучей. Берут его там, где важна отзывчивость: торговые системы, игровые серверы, крупные веб-сервисы.
Как включить ZGC?
Флагом виртуальной машины
-XX:+UseZGC. По умолчанию в JDK начиная с девятой версии работает G1, поэтому ZGC нужно выбирать явно. Отдельный флаг для поколенческого режима больше не нужен: с JDK 24 это единственный режим ZGC.
Чем ZGC отличается от G1?
Приоритетами. G1 ищет баланс между паузами и общей производительностью, а ZGC жертвует пропускной способностью ради пауз: по измерениям она примерно на 10 процентов ниже. Если приложение считает данные пакетами и паузы ему безразличны, G1 обычно выгоднее. Если пользователь ждет ответа на экране, выигрывает ZGC.
Что такое поколенческий ZGC?
Это режим, в котором сборщик хранит молодые и старые объекты раздельно и чаще обходит молодые. Большинство объектов в Java умирает почти сразу, поэтому такой обход заметно дешевле. Появился режим в JDK 21, стал умолчанием в JDK 23, а в JDK 24 остался единственным.
Какой размер кучи указывать для ZGC?
Главный параметр это максимальный размер кучи
-Xmx. Он должен вмещать живые данные приложения плюс запас, в котором сборщик будет работать: чем больше свободного места, тем реже запускается сборка. Остальные параметры ZGC подбирает сам, подстраиваясь под нагрузку.
Когда ZGC брать не стоит?
Когда у приложения нет требований к задержке, а есть требования к объему обработанных данных: пакетная обработка, расчеты, сборка отчетов ночью. Там десять процентов пропускной способности важнее, чем короткие паузы, и разумнее оставить G1. Не стоит менять сборщик и наугад: сначала измерьте паузы, потом выбирайте.
Читайте также
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ