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

JEP 350: Dynamic CDS Archives

Динамические архивы CDS

AuthorsJiangli Zhou, Ioi Lam, Calvin Cheung
ОтветственныйCalvin Cheung
ТипFeature
ОбластьJDK
СтатусClosed / Delivered
Выпуск13
Компонентhotspot / runtime
Обсуждениеhotspot dash dev at openjdk dot java dot net
ТрудоёмкостьL
ДлительностьM
Связан сJEP 310: Application Class-Data Sharing
РецензентыKaren Kinnear
ОдобренMikael Vidstedt
Создан2018/12/12 19:28
Обновлён2021/10/14 17:08
Задача8215311

Аннотация

Расширить совместное использование данных классов приложения (application class-data sharing), чтобы классы можно было динамически архивировать в конце выполнения Java-приложения. В архив попадут все загруженные классы приложения и классы библиотек, которых нет в базовом слое — архиве CDS по умолчанию.

Цели

  • Упростить использование совместного доступа к данным классов приложения (AppCDS). Избавить пользователей от необходимости делать пробные запуски, чтобы создать список классов для каждого приложения.

  • Статическое архивирование по списку классов, включаемое параметром -Xshare:dump, должно по-прежнему работать. Это касается классов как встроенных загрузчиков классов, так и пользовательских.

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

  • Архивируются только классы, загруженные во время выполнения приложения. Класс, который есть в JAR-файле, но не загружался во время выполнения, в архив не попадёт.

  • Объекты в куче Java, созданные во время выполнения приложения, динамически архивироваться не будут.

  • Динамическое архивирование не выполняется, если приложение завершается аварийно, например при сбое.

Мотивация

Архивирование классов приложения с помощью AppCDS в HotSpot дополнительно сокращает время запуска и расход памяти по сравнению с архивом CDS по умолчанию. Однако сейчас, чтобы использовать AppCDS для Java-приложения, нужно выполнить три шага:

  1. Сделать один или несколько пробных запусков, чтобы создать список классов
  2. Выгрузить архив по созданному списку классов
  3. Запустить приложение с архивом

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

Динамическое архивирование, включаемое параметром командной строки, упростит работу с AppCDS: пробные запуски (шаг 1 выше) станут не нужны, а встроенные и пользовательские загрузчики классов будут поддерживаться одинаково эффективно.

В последующем улучшении этого JEP архив мог бы создаваться автоматически при первом запуске приложения. Тогда отпал бы и отдельный шаг создания архива (шаг 2 выше). Использование CDS/AppCDS могло бы стать полностью прозрачным и автоматическим.

Описание

Поддерживаемые конфигурации архивов

Во время выполнения будут поддерживаться следующие конфигурации:

  • Статический базовый архив (архив CDS по умолчанию) + динамический архив — когда оба архива успешно отображены в память
  • Только статический базовый архив — когда динамический архив не удаётся отобразить в память

Сейчас динамическому архиву нужен архив CDS по умолчанию в качестве базового. Если базовый архив не удаётся отобразить в память и использовать во время выполнения, динамический архив верхнего слоя автоматически отключается.

Архивирование классов при завершении

Если указан параметр -XX:ArchiveClassesAtExit, общий архив динамически создаётся при завершении приложения.

Динамически создаваемый архив строится поверх системного архива по умолчанию, входящего в образ запущенного JDK. Для каждого приложения создаётся отдельный файл архива верхнего слоя. Имя файла динамического архива пользователь может задать аргументом параметра -XX:ArchiveClassesAtExit. Например, следующая команда создаёт hello.jsa:

% bin/java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello

Чтобы запустить то же приложение с этим динамическим архивом:

% bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello

Зависимость от базового слоя

Динамически созданный архив верхнего слоя зависит от архива базового слоя (то есть содержит указатели на данные базового слоя), поэтому в верхнем слое записываются значения CRC заголовка базового архива и всех общих пространств.

Во время выполнения, когда динамический архив отображается в память, все записанные значения CRC сравниваются со значениями CRC отображённого сейчас базового архива. Если какое-либо значение CRC не совпадает, динамический архив отключается, а отображённый базовый архив продолжает использоваться.

Проверка зависимости от базового архива по значениям CRC надёжнее, чем проверка имени, размера и времени изменения файла.

Копирование и перемещение метаданных классов

Все загруженные классы приложения и классы библиотек (кроме тех, что входят в базовый слой) динамически архивируются в верхний слой. Сейчас метаданные классов копируются и перемещаются в конце выполнения приложения, перед завершением VM. Из архивируемых данных удаляется вся информация, которую нельзя использовать совместно.

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

Общие пространства в динамических архивах

Структура динамического архива похожа на существующий статический архив. Метаданные разделены на следующие четыре пространства. Пространство «md» не требуется.

  • rw: данные для чтения и записи
  • ro: данные только для чтения
  • mc: трамплины

Во время выполнения общие пространства отображаются в память по отдельности. Пространство «ro» отображается только для чтения, чтобы его могли совместно использовать разные процессы.

Экономия памяти

Если на одном хосте работает несколько связанных процессов, совместное использование памяти можно улучшить с помощью двух уровней архивов. Например, если есть такие программы, использующие один и тот же набор библиотек:

2 процесса, запущенных с «-cp:lib.jar:foo.jar FooApp»

4 процесса, запущенных с «-cp:lib.jar:bar.jar BarApp»

можно создать статический архив (по списку классов) только для классов из lib.jar (и других системных классов, которые используют эти приложения). Затем создать два разных динамических архива: один для приложения «foo», другой для приложения «bar».

Так статический архив будет общим для всех 6 процессов, а динамические архивы будут общими для процессов, выполняющих одну и ту же программу.

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

При динамическом архивировании метаданные классов можно было бы копировать и перемещать сразу после загрузки запрошенного класса. Перемещение метаданных классов в пространства архива можно было бы выполнять в конце выполнения приложения, перед завершением VM, перенося данные в пространства архива.

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

  • Нужно выполнить все существующие тесты CDS и AppCDS, чтобы убедиться, что статическое архивирование по списку классов работает.
  • Нужно разработать новые тесты динамического архивирования как со встроенными, так и с пользовательскими загрузчиками классов.