← Recipes

Compact Object Headers

Use Java 25 compact object headers to reduce per-object heap overhead in object-dense workloads.

Flags

-XX:+UseCompactObjectHeaders-Xlog:gc*

-XX:+UseCompactObjectHeaders enables the Java 25 compact object header layout. The goal is to reduce the memory used by each Java object header, which can lower heap footprint when an application keeps many small objects alive.

Flag details

-XX:+UseCompactObjectHeaders
Enables compact object headers. In Java 25 this is a product feature, so the Java 24 experimental unlock pattern is no longer required for the Java 25 recipe.
-Xlog:gc*
Records heap occupancy and GC behavior so you can compare memory pressure before and after changing the object header layout.

How it works

Every Java object has a header that stores VM metadata such as locking state, identity hash information, age, and class information. On 64-bit HotSpot, traditional object headers use more space than many tiny application objects need for their actual fields.

Compact Object Headers reduce the object header footprint to 64 bits. The largest benefit appears in object-dense heaps: maps, graph structures, ASTs, caches, deserialized records, messaging payloads, and domain models with many small objects.

This is a memory-layout flag, not a garbage collector. It can be combined with G1, ZGC, or another collector, but you should benchmark the exact workload before rolling it out.

When to use it

Use this when heap histograms, JFR allocation data, or object-layout tools show that the application retains many small Java objects. It is especially interesting when memory cost is driven by object count rather than large arrays or byte buffers.

It is less likely to help workloads dominated by large primitive arrays, direct buffers, off-heap memory, or a few large object graphs where header overhead is a small fraction of total memory.

Java version support

Compact Object Headers were experimental in Java 24 and required -XX:+UnlockExperimentalVMOptions. In Java 25 they are a product feature and can be enabled directly with -XX:+UseCompactObjectHeaders. They are not the default object-header layout in Java 25.

Related JEPs

Examples

Enable compact object headers on Java 25

java -XX:+UseCompactObjectHeaders \
  -Xlog:gc*:file=logs/gc-compact-headers.log:time,uptime,level,tags \
  -jar app.jar

Use this for a staging run against the same traffic profile as the baseline.

Compare with a normal memory-footprint launch

java -Xmx2g \
  -Xlog:gc*:file=logs/gc-baseline.log:time,uptime,level,tags \
  -jar app.jar

java -Xmx2g -XX:+UseCompactObjectHeaders \
  -Xlog:gc*:file=logs/gc-compact-headers.log:time,uptime,level,tags \
  -jar app.jar

Keep heap size and traffic constant so the comparison isolates the object-header layout.

Combine with a collector choice

java -XX:+UseG1GC -XX:+UseCompactObjectHeaders -Xmx4g \
  -jar object-dense-service.jar

The compact-header flag changes object layout; the GC flag still controls collection policy.

Verify

References

See JEP 519: Compact Object Headers and the Oracle Java 25 GC tuning guide section on compact object headers.