Flags
-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.
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
- Compare live-set size after full or old-generation collection, not only startup RSS.
- Check p95 and p99 latency because changing layout can shift cache behavior and GC timing.
- Use JFR, heap histograms, or object layout tools to confirm the workload is object-dense.
- Run the same workload with and without the flag before changing production defaults.
References
See JEP 519: Compact Object Headers and the Oracle Java 25 GC tuning guide section on compact object headers.