AOT Cache in Java 24 and 25: Faster Startup
Introduction
Every time a Java application starts, the JVM repeats the same work: it reads, parses, verifies and links hundreds or thousands of classes, runs their static initializers, and starts out interpreting code until the JIT compiler has gathered enough profile data to compile the hot methods. For long-running servers this warm-up hardly matters, but for command-line tools, serverless functions and containers which are started and stopped often, it is a large part of their total cost. Project Leyden's first results attack this with an ahead-of-time (AOT) cache: you run the application once in a training run, the JVM records what it did, and every later start reuses that work. Java 24Click to read tutorial: Overview of New Features in Java 24 (JEP 483) added AOT class loading and linking, and Java 25Click to read tutorial: Overview of New Features in Java 25 made it a single step (JEP 514) and added method profiles (JEP 515). This tutorial explains the AOT cache with a runnable example, measuring the startup improvement on both versions.
What the AOT cache stores
The AOT cache builds on class-data sharing (CDS)Click to read: class-data sharing (CDS), which since Java 10 has let the JVM map pre-parsed classes from an archive. CDS stores classes in their loaded state. The AOT cache goes further -
The AOT cache works with applications on a class path of JAR files, so the program is packaged in
OUTPUT without an AOT cache (JDK 24)
Creating an AOT cache in Java 24: two steps
In Java 24, creating a cache takes a training run which records an AOT configuration, followed by a step which creates the cache from it. The training run should exercise the application the way production does - for a server, for example, by sending it typical requests -
OUTPUT of the create step
Then every production run uses the cache with
OUTPUT with the AOT cache (JDK 24)
Java 25: one step, and method profiles
Java 25 (JEP 514) made the common case a single command:
OUTPUT without an AOT cache (JDK 25)
OUTPUT with the AOT cache (JDK 25)
Explanation of the results
Rules and limitations
- Java 24: classes are stored already loaded and linked, so at startup the JVM finds them in the state they had in the training run, ready to use, with no loading, verification or linking work.
- Java 25: the cache also stores method profiles - the statistics the JIT compiler gathers about which methods are hot and which paths they take - so the JIT can compile the right methods immediately instead of first collecting profiles, reducing warm-up time.
An application which reports its own startup time
//App.java
import java.net.URI;
import java.net.http.HttpRequest;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.TreeMap;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class App {
public static void main(String[] args) {
Logger.getLogger("app").fine("starting");
var groups = IntStream.range(0, 1000).boxed()
.collect(Collectors.groupingBy(i -> i % 7, TreeMap::new, Collectors.summingInt(i -> i)));
var request = HttpRequest.newBuilder(URI.create("http://localhost/")).build();
String date = LocalDate.of(2025, 9, 16).format(DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.US));
long ms = Duration.between(ProcessHandle.current().info().startInstant().orElseThrow(), Instant.now()).toMillis();
System.out.println("Groups: " + groups.size() + ", request: " + request.method()
+ ", Java 25 released " + date + " | JVM start to done: " + ms + " ms");
}
}
javac -d classes App.java jar --create --file app.jar --main-class App -C classes .
app.jar. Without a cache, a run looks like this -
java -cp app.jar App
Groups: 7, request: GET, Java 25 released 16 September 2025 | JVM start to done: 235 ms
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -cp app.jar App java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot -cp app.jar
AOTCache creation is complete: app.aot
-XX:AOTCache -
java -XX:AOTCache=app.aot -cp app.jar App
Groups: 7, request: GET, Java 25 released 16 September 2025 | JVM start to done: 143 ms
-XX:AOTCacheOutput performs the training run and creates the cache when the application exits, and the cache now also contains method profiles (JEP 515) -
java -XX:AOTCacheOutput=app25.aot -cp app.jar App java -XX:AOTCache=app25.aot -cp app.jar App
Groups: 7, request: GET, Java 25 released 16 September 2025 | JVM start to done: 213 ms
Groups: 7, request: GET, Java 25 released 16 September 2025 | JVM start to done: 144 ms
- The timings are single runs on a Windows laptop and vary from run to run, but over several runs the AOT cache consistently cut the time from JVM start to the end of the work by around a quarter to a third on this small program. Larger applications, which load thousands of classes - such as a Spring Boot service - benefit more; JEP 483 reports a Spring application starting about 40% faster.
- The JDK 25 runs used the Eclipse Temurin JDK 25, while the Java 24 runs used Oracle's JDK 24, so compare each version's runs with each other rather than across versions.
- The cache file is around 13 MB for this program, since it contains every class the training run used, in their loaded and linked state.
- The cache must be used with the same JDK build, the same operating system and architecture, and the same class path as the training run (more JARs may be appended at the end). If they do not match, the JVM ignores the cache with a warning and starts normally - it never runs incorrectly.
- Classes the training run never loaded are not in the cache, so a representative training run matters.
- The cache can also hold pre-built Java objects from the heap. In Java 24 and 25 that part could not be used with ZGC; Java 26 (JEP 516) made AOT object caching work with any garbage collector.
- Class paths must contain JAR files, not directories of class files.
-XX:AOTMode=record and -XX:AOTMode=create, and in Java 25 in one step with -XX:AOTCacheOutput, which also stores method profiles for the JIT compiler. We measured the startup improvement on both versions, and went through the rules for using a cache. Next, read about virtual threads in synchronized code without pinningClick to read tutorial: Java 24: Virtual Threads in synchronized Without Pinning.Continue Reading Java 22 to 25 Tutorials
Overview of New Features in Java 24Click to read tutorial: Overview of New Features in Java 24 Java 24 Stream Gatherers Tutorial with ExamplesClick to read tutorial: Java 24 Stream Gatherers Tutorial with Examples Java 24 Class-File API Tutorial with ExamplesClick to read tutorial: Java 24 Class-File API Tutorial with Examples Java 24: Virtual Threads in synchronized Without PinningClick to read tutorial: Java 24: Virtual Threads in synchronized Without Pinning Java 24 Quantum-Resistant Crypto: ML-KEM and ML-DSAClick to read tutorial: Java 24 Quantum-Resistant Crypto: ML-KEM and ML-DSA Overview of New Features in Java 22Click to read tutorial: Overview of New Features in Java 22 Overview of New Features in Java 23Click to read tutorial: Overview of New Features in Java 23 Overview of New Features in Java 25Click to read tutorial: Overview of New Features in Java 25 Java 22 Foreign Function & Memory API TutorialClick to read tutorial: Java 22 Foreign Function & Memory API Tutorial
Overview of New Features in Java 24Click to read tutorial: Overview of New Features in Java 24 Java 24 Stream Gatherers Tutorial with ExamplesClick to read tutorial: Java 24 Stream Gatherers Tutorial with Examples Java 24 Class-File API Tutorial with ExamplesClick to read tutorial: Java 24 Class-File API Tutorial with Examples Java 24: Virtual Threads in synchronized Without PinningClick to read tutorial: Java 24: Virtual Threads in synchronized Without Pinning Java 24 Quantum-Resistant Crypto: ML-KEM and ML-DSAClick to read tutorial: Java 24 Quantum-Resistant Crypto: ML-KEM and ML-DSA Overview of New Features in Java 22Click to read tutorial: Overview of New Features in Java 22 Overview of New Features in Java 23Click to read tutorial: Overview of New Features in Java 23 Overview of New Features in Java 25Click to read tutorial: Overview of New Features in Java 25 Java 22 Foreign Function & Memory API TutorialClick to read tutorial: Java 22 Foreign Function & Memory API Tutorial