Skip to main content

Command Palette

Search for a command to run...

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

Updated
3 min read
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:

ComponentPurpose
Mark WordStores object state: hashcode, GC age, lock info
Class PointerPoints to the class metadata (methods, type info)
Array LengthOnly 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:

JVMMemory per objectTotal memory for 1M objects
Java 1716 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.