What Is an Object Header? Every single Java object — every String, every Integer, every record, every array — carries a header that the JVM uses for bookkeeping. Your code never sees this header; it lives alongside the object’s fields in memory. Before Java 25, on a 64-bit JVM, the header occupied 96 to 128 bits (12–16 bytes): ┌─────────────────────────────────────────────────────────┐ │ Mark Word (64 bits) │ │ ─ identity hash code │ │ ─ lock state (biased lock / thin lock / fat lock) │ │ ─ GC age bits │ ├─────────────────────────────────────────────────────────┤ │ Class Pointer (32 bits compressed / 64 bits full) │ │ ─ pointer to the object's class (Klass* in HotSpot) │ └─────────────────────────────────────────────────────────┘ With UseCompressedOops (default), the class pointer is compressed to 32 bits, giving a 96-bit (12-byte) header.
Continue reading »Memory
2 posts in this section
Foreign Function & Memory API (JEP 442): Calling Native Code Without JNI
Preview Feature in Java 21 — Finalized in Java 22 (JEP 454). The API shown here is the Java 21 preview version; it is nearly identical to the final API. Why Replace JNI? Java Native Interface (JNI) has been the standard way to call native code since Java 1.1. It works but is notoriously painful: Requires writing C wrapper code for every native call Native method signatures must exactly match Java declarations (or you get silent crashes) Memory management is manual — leak native memory once and you have a slow memory leak JNI calls disable JIT optimizations around the call site Debugging native crashes through JNI is extremely difficult The Foreign Function & Memory (FFM) API replaces all of this: call native functions directly from Java, manage native memory safely with automatic lifetime management, and do it without writing a single line of C.
Continue reading »