openjdk.ruOpenJDK на русском

JEP 304: Garbage Collector Interface

Интерфейс сборщика мусора

ОтветственныйRoman Kennke
ТипFeature
ОбластьImplementation
СтатусClosed / Delivered
Выпуск10
Компонентhotspot / gc
Обсуждениеhotspot dash gc dash dev at openjdk dot java dot net
ТрудоёмкостьL
ДлительностьM
БлокируетJEP 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)
Связан сJEP 318: Epsilon: A No-Op Garbage Collector (Experimental)
РецензентыAleksey Shipilev, Erik Helin, Erik Österlund, Mikael Vidstedt, Per Liden
ОдобренMikael Vidstedt
Создан2016/08/06 08:45
Обновлён2018/04/09 12:37
Задача8163329

Аннотация

Улучшить изоляцию исходного кода разных сборщиков мусора за счёт чистого интерфейса сборщика мусора (GC).

Цели

  • Повысить модульность внутреннего кода GC в HotSpot
  • Упростить добавление нового GC в HotSpot без изменений в существующей кодовой базе
  • Упростить исключение GC из сборки JDK

Что не является целью

  • Добавление или удаление какого-либо GC не является целью.
  • Эта работа продвинет изоляцию алгоритмов GC в HotSpot на этапе сборки, но полностью добиться такой изоляции не является целью (это задача другого JEP).

Критерии успеха

  • Реализация будет считаться успешной, если реализации GC в основном находятся в исходных файлах в соответствующих каталогах src/hotspot/share/gc/$NAME и, возможно, в каталоге src/hotspot/cpu/share/gc/$NAME. Код за пределами этих каталогов должен как можно меньше подключать файлы из них, а специфичных для отдельных GC ветвлений if-else должно быть совсем немного.
  • Производительность не должна ухудшиться из-за этого рефакторинга.

Мотивация

Сейчас реализация каждого сборщика мусора состоит из исходных файлов в своих каталогах src/hotspot/share/gc/$NAME: например, G1 находится в src/hotspot/share/gc/g1, CMS — в src/hotspot/share/gc/cms и т. д. Однако отдельные фрагменты разбросаны по всему исходному коду HotSpot. Например, большинству GC нужны определённые барьеры, которые требуется реализовать в среде выполнения, интерпретаторе, C1 и C2. Эти барьеры находятся не в каталоге конкретного GC, а реализованы в общем исходном коде интерпретатора, C1 и C2 (часто под защитой длинных цепочек if-else). Та же проблема касается, например, диагностического кода, такого как MemoryMXBeans. У такой организации исходного кода есть несколько недостатков:

  1. Разработчикам GC для реализации нового сборщика мусора нужно знать обо всех этих местах и о том, как расширить их под свои нужды.
  2. Разработчикам HotSpot, которые не занимаются GC, трудно понять, где искать определённый фрагмент кода для заданного GC.
  3. Трудно исключить на этапе сборки отдельные сборщики мусора. #define INCLUDE_ALL_GCS давно служит способом собрать JVM только со встроенным последовательным сборщиком (serial collector), но этот механизм становится слишком негибким.

Более чистый интерфейс GC значительно упростил бы реализацию новых сборщиков, сделал бы код намного чище и упростил бы исключение одного или нескольких сборщиков на этапе сборки. Добавление нового сборщика мусора должно сводиться к реализации хорошо документированного набора интерфейсов, а не к поиску всех мест в HotSpot, которые нужно изменить.

Описание

Интерфейс GC будет определяться существующим классом CollectedHeap, который должен реализовать каждый сборщик мусора. Класс CollectedHeap будет управлять большинством аспектов взаимодействия между сборщиком мусора и остальной частью HotSpot (есть несколько вспомогательных классов, которые нужны до создания экземпляра CollectedHeap). Точнее, реализация сборщика мусора должна будет предоставить:

  • Кучу — подкласс CollectedHeap
  • Набор барьеров — подкласс BarrierSet, реализующий различные барьеры для среды выполнения
  • Реализацию CollectorPolicy
  • Реализацию GCInterpreterSupport, которая реализует различные барьеры GC для интерпретатора (с помощью ассемблерных инструкций)
  • Реализацию GCC1Support, которая реализует различные барьеры GC для компилятора C1
  • Реализацию GCC2Support, которая реализует различные барьеры GC для компилятора C2
  • Инициализацию возможных аргументов, специфичных для GC
  • Настройку MemoryService, связанных пулов памяти, менеджеров памяти и т. д.

Код деталей реализации, общих для нескольких сборщиков мусора, должен находиться во вспомогательном классе. Так его смогут легко использовать разные реализации GC. Например, может существовать вспомогательный класс, реализующий различные барьеры для поддержки таблицы карт (card table), и любой GC, которому нужны пост-барьеры таблицы карт, будет вызывать соответствующие методы этого вспомогательного класса. Так интерфейс даёт гибкость для реализации совершенно новых барьеров и в то же время позволяет повторно использовать существующий код, комбинируя его по принципу «mix-and-match».

Альтернативы

В качестве альтернативы можно продолжать использовать текущую архитектуру. Скорее всего, это будет работать ещё какое-то время, но будет мешать дальнейшей разработке новых алгоритмов GC и удалению старых.

Тестирование

Это чистый рефакторинг. Всё, что работало раньше, должно работать и после него, а производительность не должна ухудшиться. Должно быть достаточно запуска стандартных наборов регрессионных тестов; разрабатывать новые тесты не требуется.

Риски и допущения

Риск низкий: в основном это рефакторинг внутреннего кода HotSpot. Существует риск, что пострадает производительность, например если будут добавлены дополнительные виртуальные вызовы. Этот риск можно снизить с помощью непрерывного тестирования производительности.

Зависимости

Этот JEP поможет с JEP 291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector, поскольку даёт способ изолировать этот сборщик и позволяет при необходимости передать его сопровождение другим.

Этот JEP также поможет с JEP 189: Shenandoah: An Ultra-Low-Pause-Time Garbage Collector и сделает его изменения менее инвазивными.