Files
javademos/docs/03-compact-headers.md

37 lines
2.4 KiB
Markdown

# 3. Compact object headers are the default (JEP 534)
Prev: [2. G1](02-g1-default.md) · Next: [4. Post-quantum TLS](04-post-quantum-tls.md)
Every Java object starts with a header. On JDK 26 with default settings it is **12 bytes** (8 bytes mark word plus a 4-byte compressed class pointer).
With compact object headers the two are squeezed into **8 bytes**. JEP 534 makes that the default in 27; `-XX:-UseCompactObjectHeaders` turns it off.
## Measured with JOL
[`scripts/object-headers.sh`](../scripts/object-headers.sh) downloads JOL 0.17 (sha1-checked) and runs [`HeaderDemo`](../object-headers/src/HeaderDemo.java) three ways.
The summary is [15](output/15-headers-summary.txt); raw runs are [10](output/10-headers-jdk26.txt) (26), [11](output/11-headers-jdk27.txt) (27),
[12](output/12-headers-jdk27-opt-out.txt) (27 with the opt-out, which reproduces 26 exactly).
| Object | JDK 26 | JDK 27 |
|---|---|---|
| `Object` | 16 B | 8 B |
| `Point { int x; int y; }` | 24 B | 16 B |
| `Order { long id; int quantity; boolean paid; String customer; }` | 32 B | 32 B |
| boxed `Long` | 24 B | 16 B |
| boxed `Integer` | 16 B | 16 B |
| `int[3]` | 32 B | 24 B |
| 1,000,000 boxed `Long` in an `ArrayList` | 28.9 MB | 20.9 MB |
| 1,000,000 `Point` in an `ArrayList` | 28.9 MB | 20.9 MB |
| 1,000,000 boxed `Integer` in an `ArrayList` | 20.9 MB | 20.9 MB |
The pattern to notice: saving 4 bytes only helps when it crosses an 8-byte alignment boundary. `Order` and boxed `Integer` do not move, because padding
was already absorbing the difference. Your heap will not shrink by "4 bytes times object count"; it shrinks by the number of objects that were sitting just past a boundary.
## Two things that bite
* **JOL 0.17 cannot inspect a `record`.** `Unsafe.objectFieldOffset` refuses records ([13](output/13-jol-record-failure.txt)). The workaround
`-Djol.magicFieldOffset=true` prints a layout but shows the header mark as `N/A` ([14](output/14-jol-record-workaround.txt)).
* **Anything that hard-codes 12 bytes** (off-heap size estimators, "object overhead" constants in capacity plans, tests that assert `Instance size`) is now wrong by default.
`-XX:+UseCompressedClassPointers` is also no longer an option in 27: the JVM prints "Ignoring option UseCompressedClassPointers; support was removed in 27.0" ([60](output/60-removed-options.txt)).
Prev: [2. G1](02-g1-default.md) · Next: [4. Post-quantum TLS](04-post-quantum-tls.md)