diff --git a/docs/src/main/asciidoc/aot.adoc b/docs/src/main/asciidoc/aot.adoc new file mode 100644 index 0000000000000..a936519fedbf7 --- /dev/null +++ b/docs/src/main/asciidoc/aot.adoc @@ -0,0 +1,203 @@ +//// +This guide is maintained in the main Quarkus repository +and pull requests should be submitted there: +https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc +//// += Ahead-of-Time (AOT) Caching +include::_attributes.adoc[] +:categories: core, cloud +:summary: This guide explains how to use Leyden AOT caching with Quarkus for dramatically faster startup times on JDK 24+. +:topics: aot,leyden,startup,performance + +This guide explains how to leverage JDK's Ahead-of-Time (AOT) caching capabilities in Quarkus to achieve significantly faster application startup times. + +== Overview + +Starting with JDK 24, link:https://openjdk.org/projects/leyden/[Project Leyden] introduces powerful AOT caching capabilities (link:https://openjdk.org/jeps/483[JEP 483]) that can significantly reduce Java application startup time. +Quarkus provides first-class support for these features, making it easy to build and deploy AOT-optimized applications. + +[IMPORTANT] +==== +Leyden AOT requires **JDK 24 or newer**. For older JDK versions, Quarkus can fall back to AppCDS (see <>). +==== + +== Quick start + +To build a Quarkus application with AOT caching enabled: + +[source,bash] +---- +./mvnw verify -Dquarkus.package.jar.type=aot-jar -Dquarkus.package.jar.aot.enabled=true +---- + +NOTE: In a future Quarkus release, specifying `-Dquarkus.package.jar.type=aot-jar` will no longer be necessary - enabling AOT via `-Dquarkus.package.jar.aot.enabled=true` will automatically use the appropriate JAR type. + +Then run the application with: + +[source,bash] +---- +cd target/quarkus-app +java -XX:AOTCache=app.aot -jar quarkus-run.jar +---- + +== AOT-optimized JAR packaging + +Quarkus provides a specialized `aot-jar` packaging type designed to work optimally with JDK's AOT features. +This packaging type: + +* Structures the application for optimal AOT class loading +* Delegates all class loading to the JDK's class loaders (required for AOT to work effectively as Leyden currently does not support custom class loaders) +* Caches frequently-accessed resources (like service loader files) to avoid classpath scanning at runtime + +NOTE: It is not recommended to use the `aot-jar` packaging outside of the AOT use case, as the `fast-jar` packaging offers more optimizations that result in better performance compares to the `aot-jar` when Leyden's AOT cache is not used. + +== Generating the AOT cache + +Enable AOT cache generation with: + +[source,bash] +---- +./mvnw package -Dquarkus.package.jar.type=aot-jar -Dquarkus.package.jar.aot.enabled=true +---- + +On JDK 24+, this generates an `app.aot` file in `target/quarkus-app/`. + +=== Training with integration tests + +For optimal results, the AOT cache should be "trained" by running actual application workloads. +Quarkus can use your `@QuarkusIntegrationTest` test suite for this training: + +[source,bash] +---- +./mvnw verify -Dquarkus.package.jar.type=aot-jar -Dquarkus.package.jar.aot.enabled=true +---- + +With this approach: + +1. Quarkus builds the application +2. Integration tests run against the application with AOT training enabled +3. The JVM captures profiling data during the test run +4. An optimized `app.aot` cache is generated + +The more representative your integration tests are of production traffic, the more effective the AOT cache will be. + +=== Controlling the training phase + +The `quarkus.package.jar.aot.phase` configuration controls when training occurs: + +* `AUTO` (default): Uses `INTEGRATION_TESTS` for Leyden AOT +* `BUILD`: Generates the cache during build (limited training, faster builds) +* `INTEGRATION_TESTS`: Generates during test execution (better optimization) + +[source,bash] +---- +# Explicit integration test training +./mvnw verify -Dquarkus.package.jar.type=aot-jar -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.phase=INTEGRATION_TESTS + +# Build-time only (faster, less optimal) +./mvnw package -Dquarkus.package.jar.type=aot-jar -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.phase=BUILD +---- + +== Running with AOT cache + +Launch your application with the `-XX:AOTCache` JVM flag: + +[source,bash] +---- +cd target/quarkus-app +java -XX:AOTCache=app.aot -jar quarkus-run.jar +---- + +== Container images + +Quarkus can automatically build container images that include AOT caches, giving you fast startup times out of the box. + +=== Building AOT-enhanced container images + +When using `quarkus-container-image-jib`, `quarkus-container-image-docker`, or `quarkus-container-image-podman`: + +[source,bash] +---- +./mvnw verify -Dquarkus.package.jar.type=aot-jar \ + -Dquarkus.package.jar.aot.enabled=true \ + -Dquarkus.container-image.build=true +---- + +This will: + +1. Build your application with `aot-jar` packaging +2. Create a base container image +3. Run integration tests to train the AOT cache +4. Create a new container image with `-aot` suffix in the version of the image that includes the AOT cache, pre-configured to use it + +=== Adding the container image extension + +Add one of the following dependencies to your project: + +[source,xml] +---- + + + io.quarkus + quarkus-container-image-jib + + + + + io.quarkus + quarkus-container-image-docker + + + + + io.quarkus + quarkus-container-image-podman + +---- + +== Configuration reference + +include::{generated-dir}/config/quarkus-core_quarkus.package.adoc[opts=optional, leveloffset=+1] + +== Requirements and limitations + +* **JDK 24 or newer** is required for Leyden AOT features +* The AOT cache is **JDK version specific** - you must use the exact same JDK version at runtime as was used to generate the cache +* Generating the AOT file from the integration tests is currently only supported with the Maven extension. Support will be added for Gradle in the future +* The feature is untested on Windows environments + +[#appcds-legacy] +== AppCDS (Legacy) + +For JDK versions prior to 24, Quarkus supports link:https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#application-class-data-sharing[Application Class Data Sharing (AppCDS)] as a fallback. +AppCDS provides more modest startup improvements compared to Leyden AOT, but works on older JDKs. + +=== Generating AppCDS archive + +[source,bash] +---- +./mvnw package -Dquarkus.package.jar.aot.enabled=true -Dquarkus.package.jar.aot.type=AppCDS +---- + +This generates an `app-cds.jsa` file. + +=== Running with AppCDS + +[source,bash] +---- +cd target/quarkus-app +java -XX:SharedArchiveFile=app-cds.jsa -jar quarkus-run.jar +---- + +=== AppCDS limitations + +* The paths to the JAR and archive must match exactly between build and runtime +* The JDK version must be **exactly** the same +* AppCDS only caches class metadata, not method profiles or verification results +* Training during integration tests is not supported for AppCDS (only build-time generation) + +[TIP] +==== +The legacy `quarkus.package.jar.appcds.enabled` configuration is still supported but deprecated. +Use `quarkus.package.jar.aot.enabled=true` with `quarkus.package.jar.aot.type=AppCDS` instead. +==== diff --git a/docs/src/main/asciidoc/appcds.adoc b/docs/src/main/asciidoc/appcds.adoc deleted file mode 100644 index 45c795d5cb068..0000000000000 --- a/docs/src/main/asciidoc/appcds.adoc +++ /dev/null @@ -1,135 +0,0 @@ -//// -This guide is maintained in the main Quarkus repository -and pull requests should be submitted there: -https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc -//// -= AppCDS -include::_attributes.adoc[] -:categories: core, cloud -:summary: This reference guide explains how to enable AppCDS with Quarkus. -:topics: appcds,serverless - -This reference guide explains how to enable Application Class Data Sharing in your Quarkus applications. - -== What is Application Class Data Sharing (AppCDS)? - -link:https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#application-class-data-sharing[Application Class Data Sharing] is a JVM feature that helps reduce the startup time and memory footprint of a JVM application. -This is achieved by having the JVM create a pre-processed shared archived of classes that are loaded at startup time. -As these classes -are loaded every time the application starts, AppCDS is a conceptually simple way of improving the application startup time, -without the application itself having to be coded or configured in a specific way. -How much of an improvement depends on many factors, such as the number of classes loaded, the underlying hardware, etc. - -== Vanilla AppCDS generation - -The main downside of creating AppCDS manually for an application is that their generation requires launching the application with special flags and obtaining the archive in a step before the application is deployed to production. - -NOTE: The exact process depends on the JVM version being used, as newer JVM have incrementally made the process easier. - -This fact makes AppCDS difficult to use for real world deployments where a CI pipeline is responsible for building and deploying applications. - -== AppCDS in Quarkus - -=== Creating the archive - -Quarkus makes AppCDS generation as simple as setting the `quarkus.package.jar.appcds.enabled` configuration property to `true`. -For an example Quarkus application using Maven (assuming it is located in `/tmp/code-with-quarkus`), the AppCDS archive can be generated by simply building the application like so: - -[source,bash] ----- -./mvnw package -Dquarkus.package.jar.appcds.enabled=true ----- - -When the build completes, the output will contain (among other things) the following: - -[source] ----- -[INFO] [io.quarkus.deployment.pkg.steps.AppCDSBuildStep] Launching AppCDS creation process. -[INFO] [io.quarkus.deployment.pkg.steps.AppCDSBuildStep] AppCDS successfully created at: '/tmp/code-with-quarkus/target/quarkus-app/app-cds.jsa'. -[INFO] [io.quarkus.deployment.pkg.steps.AppCDSBuildStep] To ensure they are loaded properly, run the application jar from its directory and also add the '-XX:SharedArchiveFile=app-cds.jsa' JVM flag. -Moreover, make sure to use the exact same Java version (x.y.z) to run the application as was used to build it. ----- - -If we take a look at `/tmp/code-with-quarkus/target/quarkus-app`, among the other files, we see `app-cds.jsa`, which is the generated AppCDS archive. - -=== Using the archive - -Using the archive is done by using the `-XX:SharedArchiveFile` flag. However, a few caveats apply: - -* The paths to the Quarkus jar file and the AppCDS archive need to be exactly the same as those Quarkus used to build the archive -* The version of the JVM used to run the application must be **exactly** the same as the one used to build the Quarkus application. - -Assuming we are using the same JVM to run the application as we used to build the application, we can launch the application like so: - -[source,bash] ----- -cd target/quarkus-app -java -XX:SharedArchiveFile=app-cds.jsa -jar quarkus-run.jar ----- - -[TIP] -==== -The JVM is resilient. Faced with a situation where the archive file is not usable (for whatever reason) it will simply disable the AppCDS feature. - -If it is desirable to simply halt the execution when the archive is not usable, the following command line invocation can be used: - -[source,bash] ----- -java -Xshare:on -XX:SharedArchiveFile=app-cds.jsa -jar quarkus-run.jar ----- -==== - -[NOTE] -==== -Given what was mentioned above about how the application needs to be launched in order for the archive to be built, the question arises of how Quarkus deals with this situation. - -The answer is that at application build time, right after the application archive is built, Quarkus launches the application, but only the parts of the launch process that are safe are run. -More specifically, the application is run up until the steps that actually open sockets or run application logic. - -This results in an archive generation process that, on one hand, is completely safe, but on the other hand, is unable to archive every single class that the application might need at boot time. -As a result, users are expected to get a slightly more effective archive if they manually go through the hoops of generating the AppCDS archive. -==== - -[IMPORTANT] -==== -AppCDS has improved significantly in the latest JDK releases. This means that to ensure the best possible improvements from it, make sure your projects targets the highest possible Java version (ideally 17 or 21). -==== - -[TIP] -==== -Starting with JDK 24, the JVM provides an evolution of the class-data sharing in the form of the AOT cache. -If you are building an application that will target JDK 25+ you can take advantage of this feature by adding the following system property when packaging your application: - -[source,bash] ----- --Dquarkus.package.jar.appcds.enabled=true -Dquarkus.package.jar.appcds.use-aot=true ----- - -The result of using these flags is the creation of an AOT cache file named `app.aot`. - -You can use this AOT cache when launching the application like so: - -[source,bash] ----- -cd target/quarkus-app -java -XX:AOTCache=app.aot -jar quarkus-run.jar ----- -==== - -=== Generate the AOT cache from integration tests - -Although Quarkus can generate an AOT cache file without ever running the production application, the file will not be optimal as the application was never exercised against any load. To alleviate this, -Quarkus can use the existing testsuite of tests annotated with `@QuarkusIntegrationTest` to create an AOT cache file. -See the xref:getting-started-testing.adoc#generating-an-aot-cache-during-integration-tests[corresponding section] in the Testing Guide for more details. - - -=== Usage in containers - -When building container images using the `quarkus-container-image-jib` extension, Quarkus automatically takes care of all the steps needed to generate the archive and make it usable at runtime in the container. - -This way, by simply setting `quarkus.package.jar.appcds.enabled` to `true`, containers using the generated image can benefit from a slight reduction in startup time and memory usage. - -You may see that Quarkus starts a container to generate the AppCDS archive. -It does this to ensure that the Java version of the build aligns with that of the generated container image. -It is possible to opt out of this by setting `quarkus.package.jar.appcds.use-container` to `false`. -In that case, it is your responsibility to ensure that the Java version that will run the Quarkus application matches that of the machine building it. diff --git a/docs/src/main/asciidoc/container-image.adoc b/docs/src/main/asciidoc/container-image.adoc index 2474ece43fe23..c45da046d132a 100644 --- a/docs/src/main/asciidoc/container-image.adoc +++ b/docs/src/main/asciidoc/container-image.adoc @@ -104,8 +104,8 @@ this property needs to be known very early on in the build process. ==== AppCDS -Quarkus supports generating and including an link:https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#application-class-data-sharing[Application Class Data Sharing] archive when generating a container image using Jib. -See the xref:appcds.adoc[AppCDS documentation] for more details. +Quarkus supports generating and including AOT caches (including link:https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#application-class-data-sharing[Application Class Data Sharing] archives) when generating container images. +See the xref:aot.adoc[AOT Caching documentation] for more details. [[docker]] === Docker