How Java 26's AOT Object Caching Improves Startup Performance
Problem
My Java microservice takes 15 seconds to start. Every time it scales up, there’s a noticeable delay before it can handle requests. The JVM needs time to:
- Load classes
- Initialize static fields
- JIT compile hot paths
- Build internal data structures
I wanted to understand how Java 26’s AOT Object Caching could help.
Environment
- Java 26 (non-LTS)
- Spring Boot 3.x microservice
- Deployed on Kubernetes
What Is AOT Object Caching?
AOT (Ahead-of-Time) Object Caching is part of Project Leyden, Java’s initiative to improve startup and warmup times.
Here’s the idea:
Application Start ↓Load Classes ↓Initialize Objects (slow!) ↓JIT Compilation ↓Ready to ServeApplication Start ↓Load Classes ↓Load Cached Objects (fast!) ↓Ready to ServeThe key insight: many objects don’t change between runs. Configuration maps, immutable data structures, static caches - these can be computed once and loaded directly.
What Changed in Java 26?
JEP 516 made AOT caching work with any garbage collector. Previously, it only worked with G1 or Serial GC.
Before Java 26:┌─────────────┐│ AOT Cache │ → Only G1, Serial GC└─────────────┘
After Java 26:┌─────────────┐│ AOT Cache │ → G1, ZGC, Shenandoah, Serial, Parallel└─────────────┘This matters because modern cloud applications often use ZGC for low-latency requirements. Now they can benefit from AOT caching too.
How It Works
The caching process has two phases:
Phase 1: Build Time
During the build, identify objects suitable for caching:
// Immutable configuration - perfect for cachingprivate static final Map<String, Config> CONFIG_MAP = loadFromFiles(); // Runs at build time
// Static lookup tables - good candidateprivate static final List<Rule> VALIDATION_RULES = compileRules(); // Runs at build timePhase 2: Runtime
At startup, load the pre-computed cache directly:
Build Time Runtime │ │ ▼ ▼Compute Objects Load from Cache │ (milliseconds) ▼ │Serialize to Disk ▼ │ Objects Ready ▼AOT Cache FileNo recomputation. No initialization overhead.
When Does This Help?
AOT caching helps most when:
- Cloud-native applications - Fast scaling matters
- Serverless functions - Cold start latency is critical
- Microservices - Frequent scale up/down cycles
- Development - Faster restarts during testing
When it doesn’t help much:
- Long-running monoliths
- Applications with mostly dynamic data
- Systems where startup time isn’t a concern
How to Use It
Enable AOT caching with JVM flags:
# Create cache during first runjava -XX:AOTCache=./app.aot -jar myapp.jar
# Use cache on subsequent runsjava -XX:AOTCache=./app.aot -XX:AOTCacheLoad -jar myapp.jarThe exact flags and API are still evolving. Check the JEP 516 documentation for current syntax.
Why This Matters
Java has always been criticized for slow startup. GraalVM native images solve this but require significant code changes. AOT caching is a middle ground:
Traditional JVM: ████████████████████ 15sAOT Cache: ████████ 6sNative Image: ███ 2s
Trade-offs:Native Image → Best startup, but requires refactoringAOT Cache → Good startup, minimal code changesTraditional → Slow startup, no changes neededProject Leyden’s goal is to bring native-image-like performance without the constraints. AOT Object Caching is a step toward that goal.
Summary
In this post, I showed how Java 26’s JEP 516 AOT Object Caching improves startup performance. The key points are:
- Cached objects load directly at runtime, skipping initialization
- Now works with any GC (including ZGC)
- Most beneficial for cloud-native, serverless, and microservice architectures
- Part of Project Leyden’s push toward faster JVM startup
This is a stepping stone. Watch Project Leyden for more startup optimizations in future releases.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments