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. Не стоит менять сборщик и наугад: сначала измерьте паузы, потом выбирайте.

Читайте также