JEP 483: Ahead-of-Time Class Loading & Linking
"mprove startup time by making the classes of an application instantly available, in a loaded and linked state, when the HotSpot Java Virtual Machine starts. Achieve this by monitoring the application during one run and storing the loaded and linked forms of all classes in a cache for use in subsequent runs. Lay a foundation for future improvements to both startup and warmup time."
🧠 JEP 483: Ahead-of-Time Class Loading & Linking
🔍 What is it?
JEP 483 introduces a new way to pre-link Java classes during application build or testing — before your app even starts.
It extends the existing CDS (Class Data Sharing) system by allowing the JVM to record and cache class linking steps, like:
Bytecode verification
Constant pool resolution
Method/field linking
📜 CDS (Class Data Sharing) was first introduced in:
Java 5 (JDK 1.5), released in 2004.
✅ Quick Timeline
Java 5 (2004)
CDS introduced for core JDK classes only (boot classpath)
Java 9 (2017)
AppCDS added: support for user-defined classes in the archive
Java 13+
CDS improved with support for dynamic archiving (recording class list at runtime)
Java 21+
Continuous improvements in heap object archiving, layered archives, and module support
Java 24 (JEP 483)
Ahead-of-Time class linking cache added as a separate optimization
🛠 How it works (in 3 steps)
Record linking behavior during app execution
-XX:AOTMode=record
Create a binary cache of that data
-XX:AOTMode=create
Run your app with that prelinked cache
-XX:AOTMode=on -XX:AOTCache=...
DEMO
run :
scripts/jep483/run-aot-classloading.sh
Logs:
[0.267s][info][cds,aot,link] app com.wlodar.jeeps.jep483aotclassloading.MiniApp 0xa001800
[0.267s][info][cds,aot,link] app com.wlodar.jeeps.jep483aotclassloading.Service 0xa001a18
[0.267s][info][cds,aot,link] boot1 java.nio.HeapCharBuffer 0xa009cf8
[0.267s][info][cds,aot,link] app com.wlodar.jeeps.jep483aotclassloading.Repository 0xa001c40
[0.267s][info][cds,aot,link] app com.wlodar.jeeps.jep483aotclassloading.Controller 0xa002000
[0.267s][info][cds,aot,link] app com.wlodar.jeeps.jep483aotclassloading.Formatter 0xa002228
[0.427s][info][cds,aot,link] wrote 889 class(es) for category boot1
[0.427s][info][cds,aot,link] wrote 5 class(es) for category app
AOTCache creation is complete: target/app.aot
....
[0.151s][info][cds,aot,load] app com.wlodar.jeeps.jep483aotclassloading.MiniApp
[0.155s][info][cds,aot,load] app com.wlodar.jeeps.jep483aotclassloading.Service
[0.155s][info][cds,aot,load] app com.wlodar.jeeps.jep483aotclassloading.Repository
[0.155s][info][cds,aot,load] app com.wlodar.jeeps.jep483aotclassloading.Controller
[0.155s][info][cds,aot,load] app com.wlodar.jeeps.jep483aotclassloading.Formatter
app.aotconf
com/wlodar/jeeps/jep483aotclassloading/MiniApp id: 563
com/wlodar/jeeps/jep483aotclassloading/Service id: 578
com/wlodar/jeeps/jep483aotclassloading/Repository id: 579
com/wlodar/jeeps/jep483aotclassloading/Controller id: 580
com/wlodar/jeeps/jep483aotclassloading/Formatter id: 581
@cp com/wlodar/jeeps/jep483aotclassloading/Formatter 1 2 8 15 16 21 22 27 48
@cp com/wlodar/jeeps/jep483aotclassloading/Controller 1 2 7 9 10 11 17 24 25 30 34 53
@cp com/wlodar/jeeps/jep483aotclassloading/Repository 1 2 8 15 16
@cp com/wlodar/jeeps/jep483aotclassloading/Service 1 2 7 9 10 11 16 18 19 24 31 32 37 41
@cp com/wlodar/jeeps/jep483aotclassloading/MiniApp 8 15 16 21 23 24
@cp com/wlodar/jeeps/jep483aotclassloading/MiniApp 8 15 16 21 23 24
Says:
Inside
MiniApp.class
, the JVM accessed constant pool entries #8, #15, #16, etc., during execution.
What each of those indexes actually refer to depends on the compiled .class
file.
javap -v target/classes/com/wlodar/jeeps/jep483aotclassloading/MiniApp.class
#8 = Class #10 // java/lang/System
#9 = NameAndType #11:#12 // out:Ljava/io/PrintStream;
#10 = Utf8 java/lang/System
#11 = Utf8 out
#12 = Utf8 Ljava/io/PrintStream;
#13 = String #14 // 📦 Starting MiniApp...
#14 = Utf8 📦 Starting MiniApp...
#15 = Methodref #16.#17 // java/io/PrintStream.println:(Ljava/lang/String;)V
#16 = Class #18 // java/io/PrintStream
...
#21 = Class #22 // com/wlodar/jeeps/jep483aotclassloading/Service
#22 = Utf8 com/wlodar/jeeps/jep483aotclassloading/Service
#23 = Methodref #21.#3 // com/wlodar/jeeps/jep483aotclassloading/Service."<init>":()V
#24 = Methodref #21.#25 // com/wlodar/jeeps/jep483aotclassloading/Service.run:()V
...
📦 What is app.aot
?
app.aot
?The file created by:
bashCopyEditjava \
-XX:AOTMode=create \
-XX:AOTConfiguration=app.aotconf \
-XX:AOTCache=app.aot
is a compiled AOT cache — a binary file that contains:
✅ Pre-resolved class linking and constant pool data:
Class-level metadata
Constant pool resolutions
Method handles and symbolic references
Resolved field/method/class names
Potentially some intermediate compiler structures
✅ Purpose:
This allows the JVM to:
Skip the linking and symbol resolution phase
Avoid reflection costs at startup
Preload certain method metadata and types before the app even begins
🧠 Analogy:
Think of app.aotconf
as the blueprint, and app.aot
as the compiled cache based on that blueprint.
app.aotconf
Text list of classes & CP indexes used
✅ Yes
app.aot
Binary cache for AOT linking
❌ No (JVM only)
💡 When is app.aot
used?
app.aot
used?When you run with:
bashCopyEditjava \
-XX:AOTMode=on \
-XX:AOTCache=app.aot \
-cp ...
com.example.Main
➡️ The JVM loads the .aot
file at startup, checks the current heap layout, and links in the pre-recorded class resolutions without doing it live.
Last updated