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

JEP 514: Ahead-of-Time Command-Line Ergonomics

Ahead-of-Time (заблаговременная компиляция и подготовка): эргономика командной строки

ОтветственныйJohn Rose
ТипFeature
ОбластьJDK
СтатусClosed / Delivered
Выпуск25
Компонентhotspot / runtime
Обсуждениеleyden dash dev at openjdk dot org
ТрудоёмкостьM
ДлительностьS
Связан сJEP 483: Ahead-of-Time Class Loading & Linking
РецензентыAlex Buckley, Vladimir Kozlov
ОдобренVladimir Kozlov
Создан2025/02/13 18:07
Обновлён2026/08/25 18:23
Задача8350022

Аннотация

Упростить создание AOT Cache (кэш, подготовленный заранее), ускоряющих запуск Java-приложений, за счёт упрощения команд, необходимых в типичных сценариях использования.

Цели

  • Упростить процесс создания AOT-кэша без потери выразительности.

  • Не вводить принципиально новые AOT-сценарии работы, а упростить доступ к существующим.

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

  • Вводить новые AOT-оптимизации не является целью. Мы стремимся упростить доступ ко всем AOT-оптимизациям, как существующим, так и будущим.

Мотивация

AOT-кэши, появившиеся в JEP 483, ускоряют запуск Java-приложений. Ожидается, что их польза будет расти по мере того, как проект Leyden будет добавлять в HotSpot JVM новые оптимизации, связанные с AOT.

В JDK 24 AOT-кэш создаётся в два шага: лаунчер java вызывается в двух разных режимах AOT. При первом вызове указывается режим record, и JVM наблюдает за динамикой обучающего запуска вашего приложения и записывает её в AOT-конфигурацию. При втором вызове указывается режим create, и JVM создаёт AOT-кэш на основе конфигурации, записанной во время обучающего запуска.

Вот пример такого двухшагового сценария, взятый из JEP 483:

$ java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf \
       -cp app.jar com.example.App ...

$ java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf \
       -XX:AOTCache=app.aot

После этого вы запускаете приложение, указывая только AOT-кэш:

$ java -XX:AOTCache=app.aot -cp app.jar com.example.App ...

Такой рабочий запуск приложения выполняется быстрее, потому что классы приложения не нужно обнаруживать, загружать и связывать. Они сразу доступны из кэша.

Запускать java дважды, чтобы создать AOT-кэш, неудобно. Неудобно и то, что после этого остаётся файл AOT-конфигурации — это всего лишь временный файл, который не нужен для рабочих запусков и может быть удалён.

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

Описание

Мы добавляем в лаунчер java новый параметр командной строки AOTCacheOutput, задающий выходной файл AOT-кэша. Если этот параметр используется отдельно, без других параметров AOT, лаунчер фактически разделяет свой вызов на два подвызова: первый выполняет обучающий запуск (AOTMode=record), а затем второй создаёт AOT-кэш (AOTMode=create).

Например, показанный ранее двухшаговый сценарий можно заменить одним шагом:

$ java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App ...

Для удобства при такой работе JVM создаёт временный файл для AOT-конфигурации и удаляет его по завершении.

Рабочий запуск с использованием AOT-кэша выполняется так же, как и раньше:

$ java -XX:AOTCache=app.aot -cp app.jar com.example.App ...

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

Полная спецификация этих параметров доступна здесь.

Ручное управление обучением и созданием кэша

Остаются сценарии, в которых может быть предпочтительнее двухшаговый сценарий с явным указанием режима AOT при каждом вызове (AOTMode=create, затем AOTMode=record).

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

Такое разделение труда может стать важнее по мере усложнения AOT-оптимизаций Leyden. Например, какой-нибудь будущей AOT-оптимизации может потребоваться несколько минут на создание кэша на небольшом экземпляре, но всего несколько секунд на большом.

Кроме того, в средах с ограниченными ресурсами одношаговый сценарий может работать не так, как ожидается. Подвызов, создающий AOT-кэш, использует собственную Java-кучу того же размера, что и куча обучающего запуска. В результате для выполнения одношагового сценария требуется вдвое больше памяти, чем размер кучи, указанный в командной строке. Например, если одношаговый сценарий java -XX:AOTCacheOutput=... сопровождается параметром -Xms4g -Xmx4g, задающим кучу размером 4 ГБ, то для выполнения сценария среде нужно 8 ГБ. Пользователям в средах с ограниченными ресурсами следует использовать двухшаговый сценарий, если одношаговый не завершается успешно.

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

  • Мы рассматривали комбинированный режим AOT AOTMode=record+create. Сейчас это могло бы работать, но в будущем мы можем расширить обучающие запуски так, чтобы они читали существующий AOT-кэш. Тогда параметр -XX:AOTCache=myapp.aot стал бы неоднозначным, и нам, скорее всего, всё равно пришлось бы ввести параметр AOTCacheOutput.