In Java 24, JEP 483, Ahead-of-Time Class Loading & Linking, under the auspices of Project Leyden, starts Java applications like Spring PetClinic up to 40% faster without code changes or new application constraints. It needs a training run to build a cache file that ships with the application. With GraalVM Native Image and CRaC, applications start 95-99% faster but face more constraints. Since JVM initialization is very expensive, Leyden plans more improvements.
JEP 483 extends Java's Class-Data Sharing (CDS). On every startup, the JVM processes the same Java classes from the application, libraries, and the JDK the same way. CDS stores the results of reading and parsing those classes in a read-only cache file. JEP 483 adds loaded and linked classes to that cache and calls it "AOT cache."
The training run only records the AOT configuration. It's another step to create the AOT cache. This example uses a Java compiler benchmark picked by Leyden:
java ‑XX:AOTMode=record ‑XX:AOTConfiguration=app.aotconf ‑cp JavacBenchApp.jar JavacBenchApp 50
java ‑XX:AOTMode=create ‑XX:AOTConfiguration=app.aotconf ‑XX:AOTCache=app.aot ‑cp JavacBenchApp.jar
The AOT cache app.aot
file is then ready to use:
java ‑XX:AOTCache=app.aot ‑cp JavacBenchApp.jar JavacBenchApp 50
On an Apple M1 MacBook Pro, the resulting 23 MBytes AOT cache leads to a 26% faster startup. The more classes an application loads, the higher the potential speed-up from the AOT cache. That is why frameworks like Spring Boot may especially benefit from JEP 483.
Project Leyden may combine the two steps for the AOT cache creation in the future. The Quarkus framework already does that today.
The training run could be a production run, but should at least mirror production as much as possible. Using the AOT cache requires the same JDK version, operating system, CPU architecture (such as Intel x64 or ARM), class path, and Java module options as the training run, though additional classes can be used. JEP 483 cannot cache classes from user-defined class loaders and does not work with JVMTI agents that rewrite class files using ClassFileLoadHook
or call the AddToBootstrapClassLoaderSearch
or AddToSystemClassLoaderSearch
APIs.
GraalVM Native Image is an AOT compiler that moves compilation and as much initialization as possible to build time. It produces native executables that start instantly, use less RAM, and are smaller and more secure. But these executables also have principal constraints that do not affect most applications, need longer build times, have a more expensive troubleshooting process, and require more configuration. GraalVM started in Oracle Labs, but its two Java compilers may join OpenJDK.
The OpenJDK project, Coordinated Restore at Checkpoint (CRaC), takes an application memory snapshot during a training run and uses it later, similar to how JEP 483 creates and uses the AOT cache. But unlike JEP 483, CRaC only runs on Linux and requires all files and network connections to be closed before taking a snapshot and then re-opened after restoring it. That's why it needs support from the JDK and the Java framework. While most frameworks support CRaC, only two downstream distributions of OpenJDK, Azul and Bellsoft, do. And the CRaC memory snapshot may pose security risks, as it contains passwords and credentials in clear text and is susceptible to hacking attacks.
Introduced in June 2020, the goal of Project Leyden is "to improve the startup time, time to peak performance, and footprint of Java programs." Initially, Leyden wanted to introduce the "concept of static images to the Java Platform," such as from GraalVM Native Image, but after two years with no public activity, it instead pivoted to optimizing the JIT compiler. JEP 483 is the first result of that pivot shipping.
In an October 2024 blog post, Juergen Hoeller, Senior Staff Engineer and Spring Framework project lead at Broadcom, spoke of a "strategic alignment with GraalVM and Project Leyden." JEP 483 appears to prove that: Spring and Spring Boot are the only Java frameworks mentioned, and the Spring PetClinic sample application is one of the two examples. Oracle's Per Minborg, Consulting Member of Technical Staff, Java Core Libraries, also gave a joint presentation with Spring team member Sébastien Deleuze from Broadcom in October 2024, where unreleased improvements reduced the PetClinic startup time even further.
InfoQ reached out to learn how some Java frameworks plan to support JEP 483. Here are their answers in alphabetical order of the framework name. Some answers were edited for brevity and clarity.
The Helidon team shared a blog post with benchmarks of JEP 483, CRaC, and GraalVM Native Image. It used an application in the two Helidon flavors: Helidon SE and Helidon MP. The GraalVM Native Image speed-up below uses Profile-Guided Optimization (PGO), which also requires a training run.
Application Type | JEP 483 Speed-Up | CRaC Speed-Up | GraalVM Native Image Speed-Up |
---|---|---|---|
Helidon SE | 67% | 95% | 98% |
Helidon MP | 62% | 98% | 98% |
Max Rydahl Andersen, Distinguished Engineer at Red Hat, Quarkus, and Sanne Grinovero, Quarkus founding engineer and Senior Principal Software Engineer at Red Hat, from Quarkus said the following:
We're glad to see Project Leyden progressing. Quarkus fully supports JEP 483 since it's integrated into the Java VM. The biggest challenge is the training run, which can be complex - especially in containerized environments.
To simplify this, we've made it possible to "boot" Quarkus just before the first request and then package applications with the AOT cache. This follows a similar approach to our AppCDS support.
If your JVM supports it, you can try it with:
mvn package ‑DskipTests ‑Dquarkus.package.jar.appcds.enabled=true ‑Dquarkus.package.jar.appcds.use-aot=true
Then run:
cd target/quarkus-app/ java ‑XX:AOTCache=app.aot ‑jar quarkus-run.jar
This makes it easy to get the AOT cache, as long as you are aware of the limitations around the JDK, OS, and architecture.
This provides a noticeable boost in startup time. However, project Leyden is not complete yet, and we're looking forward to several improvements which are not available yet.
As an example, early previews of Leyden had a significant tradeoff: While it started more efficiently, the memory consumption was also higher. And since Quarkus users care about memory, we didn't want to recommend using it until such aspects were addressed. The Quarkus team is working very closely with the Red Hat engineers working on OpenJDK, so we are confident that such aspects are being addressed. In fact, memory consumption has already improved significantly compared to the early days, and more improvements are scheduled.
Support for custom class loaders is another big ticket on our wishlist. Speeding up classes loaded by the system class loader is great, as that accelerates the JDK initialization. But application code and Quarkus extensions are loaded by a custom class loader, so only a subset of the application currently benefits from Leyden. We'll keep working both on our side and in collaboration with the OpenJDK team to push this further.
We're also exploring ways to make it more practical for containerized environments, where a training run isn't always a natural fit.
So yes, Quarkus supports Leyden and the AOT cache introduced in JEP 483, but we're just at the beginning of a longer journey of improvements.
Sebastien Deleuze from Spring had the following to say:
The Spring team is excited that Java 24 exposes the first benefits of Project Leyden to the JVM ecosystem for wider consumption. The AOT Cache is going to supercharge CDS that is already supported by Spring Boot. We are looking forward to further evolution likely to come in future Java versions.
The Micronaut team has not responded to our request to provide a statement.