Java 25 - Compact Object Headers – How to Save Memory in Production

Java 25 is out, and it brings some exciting improvements under the hood. One of the most impactful features for backend developers is Compact Object Headers (JEP 519).
Even if your code hasn’t changed, upgrading to Java 25 can reduce memory usage, improve CPU cache efficiency, and make garbage collection faster—all automatically.
In this post, we’ll dive deep into:
What an object header is.
Why it matters for memory-heavy applications.
How Java 25’s compact headers reduce overhead.
Practical impact and examples.
What is an Object Header?
Every Java object has a small header that stores metadata required by the JVM:
| Component | Purpose |
| Mark Word | Stores object state: hashcode, GC age, lock info |
| Class Pointer | Points to the class metadata (methods, type info) |
| Array Length | Only for arrays |
On a 64-bit HotSpot JVM, a typical object header is 12–16 bytes, sometimes larger than the actual object data.
Example:
class Point {
int x;
int y;
}
Fields = 8 bytes (2 ints)
Header = 12 bytes → padded to 16 bytes
Total object size ≈ 24 bytes
Even for tiny objects, the header overhead is significant when you create millions of instances.
Why Java 25 Compact Object Headers Matter
Java 25 introduces Compact Object Headers (JEP 519), which reduce the size of the object header by:
Packing the Mark Word and Class pointer more efficiently
Eliminating unnecessary padding
Keeping all GC and lock functionality intact
This is completely transparent to developers—no code changes are required.
Memory Layout – Before vs After
Before Java 25
┌───────────────┐
│ Mark Word │ --> 8B
├───────────────┤
│ Class Ptr │ --> 4B
│ Padding │ --> 4B
└───────────────┘
[ Object Fields ]
- Header = 12 bytes → padded to 16 bytes
After Java 25 Compact Headers
┌───────────────┐
│ Compact Header │ ← Mark + Class packed efficiently (~8B)
└───────────────┘
[ Object Fields ]
Header = ~8 bytes
Memory savings: ~50% for small objects
Practical Example
class Order {
int id;
boolean delivered;
}
List<Order> orders = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
orders.add(new Order());
}
Impact:
| JVM | Memory per object | Total memory for 1M objects |
| Java 17 | 16 bytes | ~16 MB |
| Java 25 | ~8 bytes | ~8 MB |
Saving ~8 MB per million objects just by upgrading the JVM.
How to Enable / Verify
Enabled by default on 64-bit HotSpot JVM
JVM flags (optional):
# Enable compact headers
-XX:+UseCompactObjectHeaders
# Disable compact headers
-XX:-UseCompactObjectHeaders
You can also use tools like JOL (Java Object Layout) to inspect the object size:
System.out.println(GraphLayout.parseInstance(new Order()).toPrintable());
Who Benefits Most?
Microservices creating millions of DTOs per second
Kafka consumers buffering large numbers of small messages
In-memory caches storing small objects like
Point,Order, etc.High-throughput applications where GC and memory footprint matter
Even a small reduction in object size scales up to huge savings in production environments.
Highlights
Java 25 Compact Object Headers reduce per-object memory overhead on 64-bit JVMs.
No code changes needed—simply upgrade to Java 25.
Can improve GC performance, memory usage, and CPU cache efficiency.
Ideal for high-performance, memory-sensitive applications.
