Modern Java Evolution

The Foreign Function & Memory API

FFM (final in Java 22) is Project Panama delivered: MemorySegment/Arena for safe off-heap memory with deterministic lifetimes, and Linker for calling native libraries without JNI glue. The sanctioned successor to Unsafe and direct-buffer tricks.
  • Arena.ofConfined(): single-thread scope; ofShared(): multi-thread; close frees everything at once
  • MemorySegment is bounds-checked and lifetime-checked — use-after-free throws
  • MemoryLayout describes C structs; VarHandles read/write named fields
  • Long-indexed (64-bit) addressing — past ByteBuffer's 2 GB limit
  • jextract turns .h headers into complete Java bindings
  • Replaces: JNI glue, sun.misc.Unsafe memory ops, direct-ByteBuffer lifecycle hacks
Structured off-heap data
MemoryLayout POINT = MemoryLayout.structLayout(
        ValueLayout.JAVA_DOUBLE.withName("x"),
        ValueLayout.JAVA_DOUBLE.withName("y"));
VarHandle X = POINT.varHandle(PathElement.groupElement("x"));
VarHandle Y = POINT.varHandle(PathElement.groupElement("y"));

try (Arena arena = Arena.ofConfined()) {
    MemorySegment points = arena.allocate(POINT, 1_000_000);   // 16 MB off-heap, zeroed
    for (long i = 0; i < 1_000_000; i++) {
        MemorySegment p = points.asSlice(i * POINT.byteSize(), POINT.byteSize());
        X.set(p, 0L, (double) i);
        Y.set(p, 0L, Math.sqrt(i));
    }
}   // deterministic free — no GC involvement, no finalizer roulette

Why it matters beyond native calls (Native Interop): GC-invisible data. A multi-gigabyte cache in MemorySegments adds nothing to heap marking work (Gc Fundamentals) — the technique behind low-latency stores like Chronicle, previously built on Unsafe. Memory-mapped files return MemorySegments too (channel.map(..., arena)), finally giving mapped memory deterministic unmapping.

Safety model: confined arenas make single-threaded use race-free by construction (foreign threads touching the segment throw); shared arenas allow concurrent access with your own synchronization; bounds checks JIT down to negligible cost in hot loops. The explicit unsafe escape (MemorySegment.ofAddress(...).reinterpret(...)) exists, is named accordingly, and requires --enable-native-access — auditability that Unsafe never had.

Sources
  • Core Java, Volume II: Advanced Features (13th ed.)Ch. 13.11 — Foreign Functions: A Glimpse into the Future
  • Optimizing Cloud Native Java (2nd ed.)Ch. 15 — Modern Performance and The Future