![ahead of time class loading & linking - feature image](https://www.happycoders.eu/wp-content/uploads/2024/12/ahead-of-time-class-loading-linking-1180x490.jpg)
![ahead of time class loading & linking - feature image](https://www.happycoders.eu/wp-content/uploads/2024/12/ahead-of-time-class-loading-linking-800x446.jpg)
In this article, you will learn:
- Why do large Java applications take several seconds to start?
- What is Ahead-of-Time Class Loading & Linking, and how can it improve startup time?
- Step by step: How can Ahead-of-Time Class Loading & Linking accelerate the start of an application?
- How does AoT Class Loading & Linking differ from (App)CDS?
Why Do Java Applications Start So Slowly?
Java applications are highly flexible at runtime, allowing classes to be dynamically loaded and unloaded. The dynamic compilation, optimization, and de-optimization make Java programs as fast as C code (or faster), and reflection makes frameworks like Jakarta EE, Spring Boot, Quarkus, Helidon, Micronaut, etc., possible in the first place.
But these advantages come at a price:
When starting an application, hundreds of .jar files must be unpacked, and thousands of .class files must be loaded into memory, analyzed, and linked. The static initialization code of classes must be executed, and frameworks like Jakarta EE and Spring must scan the code for annotations, instantiate beans, and execute configuration code.
Large backend applications can thus take several seconds or even minutes to start.
How Can Application Startup Be Accelerated?
Many of the initialization tasks described in the previous section are the same for each application start.
As part of Project Leyden, work is done to perform as many of these repetitive tasks as possible before starting an application.
Through JDK Enhancement Proposal 483, the first fruits of this work will be released in Java 24: Classes can now (after reading, parsing, loading, and linking) be cached in a binary file, making them available much faster in a loaded and linked state for future starts of the same application.
The developers of the feature have measured startup time reductions of up to 42%.
How Does Ahead-Of-Time Class Loading Linking Work?
To accelerate program startup through AoT Class Loading & Linking, we need to perform three steps:
- In the first step, the application is started in a so-called training run. During this, the JVM analyzes all loaded and linked classes and generates a configuration file with the relevant information about these classes.
- In the second step, the binary cache file is created using this configuration file.
- For each subsequent application start, you specify this cache file, and the application loads the classes in loaded and linked form directly from this cache.
This procedure sounds more complicated than it is. In the following, I will guide you step by step through these steps using an example application up to the accelerated start of the application.
Step-By-Step Instructions to Follow Along
In this section, I will show you how to use Ahead-of-Time Class Loading Linking using a small application.
We’ll use a simple demo program that just displays the current time.
Here, we use a simple class file with an instance main method. This way, we don’t have to define a class and can simply write void main()
instead of public static void main(String args[])
.
Download an Early-Access-Build of Java 24 (Ahead-of-Time Class Loading Linking is only available from Java 24 onwards).
Save the following source code in the file AotTest.java:
void main() {
var now = LocalDateTime.now();
var nowString = now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM));
System.out.println("Hello, it's " + nowString);
}
Code language: Java (java)
Compile the code (you must specify the options --enable-preview --source 24
because the “Simple Source Files and Instance Main Methods” feature mentioned above is still in preview stage):
javac --enable-preview --source 24 AotTest.java
Code language: plaintext (plaintext)
Create a JAR file:
jar cvf AotTest.jar AotTest.class
Code language: plaintext (plaintext)
Then start the training run with the following call:
java -XX:AOTMode=record -XX:AOTConfiguration=AotTest.conf \
--enable-preview -cp AotTest.jar AotTest
Code language: plaintext (plaintext)
This creates the configuration file AotTest.conf. You can open this file with a text editor – it contains a long list of classes and data about these classes.
Then, use the following command to create the class cache in the file AotTest.aot (this command does not execute the application again):
java -XX:AOTMode=create -XX:AOTConfiguration=AotTest.conf -XX:AOTCache=AotTest.aot \
--enable-preview -cp AotTest.jar
Code language: plaintext (plaintext)
And finally, start the application specifying the cache file to use:
java -XX:AOTCache=AotTest.aot --enable-preview -cp AotTest.jar AotTest
Code language: plaintext (plaintext)
Now, let’s compare the application’s startup time with and without cache.
First, a run without cache:
time java --enable-preview -cp AotTest.jar AotTest
Code language: plaintext (plaintext)
With five runs, I got a median runtime of 0.137 seconds.
And now a run with cache:
time java -XX:AOTCache=AotTest.aot --enable-preview -cp AotTest.jar AotTest
Code language: plaintext (plaintext)
This time, I observed a median runtime of 0.086 seconds from five runs. That is an impressive performance increase of 37%, which comes close to the 42% measured by the feature’s developers.
And What About AppCDS?
The attentive reader might wonder: What’s the difference between Ahead-of-Time Class Loading & Linking and (Application) Class Data Sharing?
Class Data Sharing (CDS) has existed since Java 5 and allows storing the JDK classes in a platform-specific binary format, from which the classes can then be loaded much faster than from .class files.
In Java 10, Application Class Data Sharing (AppCDS) was added, which allows not only JDK classes but also application classes to be stored in this binary format.
Ahead-of-Time Class Loading & Linking builds upon (App)CDS. If you looked at the file AotTest.conf earlier, you might have noticed that the header says it’s a “CDS archive dump.”
While Class Data Sharing merely reads and parses the classes and then stores them in a binary format, with AoT Class Loading & Linking, the classes are additionally – as the name suggests – loaded into Class
objects and linked.
The Leyden developers have tested both mechanisms with the Spring PetClinic. AppCDS accelerated the application’s loading time by 33%, and AoT Class Loading & Linking by 42%. So, if you’re already using AppCDS, the startup time improvement through AoT Class Loading & Linking won’t be quite as significant.
Conclusion
Java is a very flexible and powerful language, but this flexibility can lead to startup times ranging from several seconds to minutes for larger applications. During startup, Java classes are read, parsed, loaded, and linked, among other things. With Ahead-of-Time Class Loading & Linking, we can perform these steps once before the application starts, thereby – according to the developers of this feature – accelerating the actual start of the application by up to 42%.
If you try out this feature, please write about your experiences in the comments. I’m curious about your measurements and your opinion!
Do you want to stay up to date and be informed as soon as a new article is published on HappyCoders.eu? Then click here to sign up for the HappyCoders.eu newsletter.