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

JEP 310: Application Class-Data Sharing

Class-Data Sharing для классов приложения

ОтветственныйIoi Lam
ТипFeature
ОбластьImplementation
СтатусClosed / Delivered
Выпуск10
Компонентhotspot / runtime
Обсуждениеhotspot dash dev at openjdk dot java dot net
Связан сJEP 350: Dynamic CDS Archives
РецензентыKaren Kinnear, Mikael Vidstedt, Vladimir Kozlov
ОдобренMikael Vidstedt, Vladimir Kozlov
Создан2017/08/08 22:02
Обновлён2026/07/29 18:56
Задача8185996

Аннотация

Чтобы ускорить запуск и уменьшить потребление памяти, расширить существующую возможность Class-Data Sharing («CDS») так, чтобы классы приложения можно было помещать в общий архив.

Цели

  • Уменьшить потребление памяти за счёт совместного использования общих метаданных классов разными Java-процессами.

  • Сократить время запуска.

  • Расширить CDS так, чтобы архивированные классы из файла образа среды выполнения JDK ($JAVA_HOME/lib/modules) и из пути классов приложения можно было загружать встроенными загрузчиками классов platform и system.

  • Расширить CDS так, чтобы архивированные классы можно было загружать пользовательскими загрузчиками классов.

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

  • Формат хранения архива общих классов, используемый в этой реализации, не будет стандартизован.

  • В этом выпуске CDS не может архивировать классы из пользовательских модулей (например, указанных в --module-path). Мы планируем добавить такую поддержку в одном из будущих выпусков.

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

Проект будет считаться успешным, если удастся добиться (1) значительной экономии памяти, занимаемой метаданными Java-классов, в нескольких процессах JVM и (2) значительного сокращения времени запуска.

Для иллюстрации:

  • Мы можем сэкономить около 340 МБ оперативной памяти для сервера приложений Java EE из 6 процессов JVM, которые в сумме потребляют 13 ГБ оперативной памяти (~2 ГБ из них приходится на метаданные классов).

  • Мы можем сократить время запуска в бенчмарке JEdit на 20–30 %.

  • Мы можем снизить потребление оперативной памяти во встраиваемом бенчмарке Felix на 18 % в 4 процессах JVM.

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

Описание

Class-Data Sharing, появившаяся в JDK 5, позволяет заранее обработать набор классов и поместить его в файл общего архива, который затем можно отображать в память во время выполнения, чтобы сократить время запуска. Она также может уменьшить потребление динамической памяти, когда несколько JVM используют один и тот же файл архива.

Сейчас CDS позволяет загружать архивированные классы только загрузчику классов bootstrap. Application CDS («AppCDS») расширяет CDS, позволяя загружать архивированные классы встроенному загрузчику классов system (он же «app class loader»), встроенному загрузчику классов platform и пользовательским загрузчикам классов.

Анализ использования памяти крупными корпоративными приложениями показывает, что такие приложения часто загружают десятки тысяч классов загрузчиком классов приложения. Применение AppCDS к этим приложениям даст экономию памяти от десятков до сотен мегабайт на каждый процесс JVM.

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

Включение AppCDS

По умолчанию Class-Data Sharing включена только для загрузчика классов bootstrap в JVM. Укажите параметр командной строки -XX:+UseAppCDS, чтобы включить совместное использование данных классов для загрузчика классов system (он же «app class loader»), загрузчика классов platform и других пользовательских загрузчиков классов.

Определение классов для архивирования

Приложение может поставляться с большим количеством классов, но при обычной работе использовать лишь часть из них. Архивируя только используемые классы, мы можем уменьшить размер файла и потребление памяти во время выполнения. Для этого сначала запустите приложение обычным образом с -Xshare:off и с помощью параметра командной строки -XX:DumpLoadedClassList запишите все загружаемые классы.

Обратите внимание, что по умолчанию -XX:DumpLoadedClassList включает только классы, загруженные загрузчиком классов bootstrap. Следует указать параметр -XX:+UseAppCDS, чтобы также были включены классы, загруженные загрузчиками классов system и platform. Например:

java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=hello.lst -cp hello.jar HelloWorld

Создание архива AppCDS

Чтобы создать архив AppCDS, укажите параметры командной строки -Xshare:dump -XX:+UseAppCDS, передайте список классов с помощью параметра -XX:SharedClassListFile и задайте тот же путь классов, что использует ваше приложение. Также следует указать параметром -XX:SharedArchiveFile имя файла архива, в котором будут храниться классы. Обратите внимание, что если -XX:SharedArchiveFile не указан, архивированные классы будут сохранены в каталог установки JDK, что обычно нежелательно. Например:

$ java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst \
    -XX:SharedArchiveFile=hello.jsa -cp hello.jar

Использование архива AppCDS

После создания архива AppCDS его можно использовать при запуске приложения. Для этого укажите параметры командной строки -Xshare:on -XX:+UseAppCDS и параметр -XX:SharedArchiveFile с именем файла архива. Например:

$ java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa \
    -cp hello.jar HelloWorld

Несовпадение путей классов

Путь классов, используемый с -Xshare:dump, должен совпадать с путём классов, используемым с -Xshare:on, или быть его префиксом. Иначе JVM выведет сообщение об ошибке о несовпадении путей классов и откажется запускаться. Чтобы проанализировать несовпадение, можно добавить -Xlog:class+path=info в командную строку приложения, и JVM выведет подробную диагностическую информацию о том, какой путь классов ожидается и какой используется на самом деле.

Использование -Xshare:auto

AppCDS работает за счёт отображения содержимого архива в память по фиксированному адресу. В некоторых операционных системах, особенно при включённой рандомизации размещения адресного пространства (ASLR), операция отображения в память может иногда завершаться неудачей, если нужное адресное пространство недоступно. Если указан параметр -Xshare:on, JVM будет считать это ошибкой и не запустится. Чтобы приложение было устойчивее в таких ситуациях, мы рекомендуем вместо этого использовать параметр -Xshare:auto. Тогда, если JVM не удастся отобразить архив в память, она отключит AppCDS и продолжит обычное выполнение приложения.

Обратите внимание, что -Xshare:auto также отключит AppCDS при несовпадении путей классов. Поэтому мы рекомендуем сначала протестировать с -Xshare:on, чтобы убедиться, что несовпадения путей классов нет, а затем использовать -Xshare:auto в рабочей среде.

Вывод списка классов, загруженных из архива AppCDS

Чтобы узнать, какие классы были загружены из архива AppCDS, можно использовать параметр командной строки -Xlog:class+load=info: он выводит имя каждого загруженного класса и место, откуда класс загружен. Классы, загруженные из архива CDS, будут выведены как source: shared objects file. Например:

$ java -Xshare:on   -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa \
    -cp hello.jar -Xlog:class+load=info HelloWorld | grep HelloWorld
[0.272s][info][class,load] HelloWorld source: shared objects file

Реализация

  • Загрузчики классов platform и system: HotSpot VM распознаёт запросы на загрузку классов от встроенных загрузчиков классов platform и system. Когда эти загрузчики запрашивают класс, который есть в архиве CDS, VM пропускает обычные этапы разбора и верификации class-файла и загружает архивированную копию класса.

  • Пользовательские загрузчики классов: когда пользовательский загрузчик классов вызывает ClassLoader::defineClass, VM пытается сопоставить содержимое class-файла с архивированным классом, сравнивая отпечатки данных class-файла. Если совпадение найдено, VM пропускает этапы разбора и верификации class-файла и напрямую загружает архивированную копию класса.

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

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

Вместо этого мы решили сделать совместное использование данных классов приложения более статическим:

  • Требуется дополнительный этап «dump».

  • При обновлении JAR-файлов приложения этап dump нужно повторить.

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

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

Необходимо обширное тестирование, чтобы обеспечить совместимость и подтвердить выигрыш в производительности.

Тестирование следует проводить на всех поддерживаемых платформах. На некоторых платформах (особенно Windows/x86) тесты могут завершаться неудачей, если JVM не может отобразить архив из-за рандомизации размещения адресного пространства (ASLR).

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

Ранее AppCDS была реализована в Oracle JDK для JDK 8 и JDK 9. Этот JEP переносит исходный код в открытый репозиторий, чтобы сделать эту возможность общедоступной. Поскольку AppCDS прошла обширное тестирование в JDK 8 и JDK 9, риск для совместимости и стабильности невелик.