Serguey Asael Shinder: JDK 28 pools small off-heap allocations, cutting confined-arena latency up to 90%
Oracle's Per-Ake Minborg has described a JDK 28 change that makes allocating small blocks of off-heap memory through the Foreign Function & Memory API dramatically cheaper — typically 6 to 18 times faster, reducing allocation latency by up to 90%, on Windows, macOS and Linux. It needs no source changes, and the safety guarantees of confined arenas are preserved. The report is on inside.java, dated 23 October 2026.
The target is a pattern anyone using the FFM API will recognise: a confined arena opened as scratch space around a native call, allocating just enough for a pointer, an int, or a short string to receive a result — handling errno is the canonical case.
try (Arena arena = Arena.ofConfined()) {
MemorySegment result = arena.allocate(ValueLayout.JAVA_INT);
nativeFunction.invokeExact(result);
return result.get(ValueLayout.JAVA_INT, 0);
}

Before JDK 28, even that tiny allocation went through the regular native allocator and registered a cleanup action — bookkeeping that could cost more than using the memory. Instrumentation during development found the pattern pervasive: in one test-suite run, over 99.99% of confined arenas that allocated anything used fewer than 64 bytes.
The fix is a per-thread cache of small native-memory pools — by default four pools of 64 bytes. A confined arena acquires a pool lazily, only on its first allocation that can benefit, so arenas that never allocate cost nothing. Once acquired the pool is owned exclusively by that arena, and allocations are carved from it sequentially; anything too large or oddly aligned falls back to the normal path, making pooling a pure opportunistic win. On close, the used portion is cleared and the pool returns to the thread cache, or to the allocator if the cache is full. Virtual threads, which cannot each carry a native cache without ruining their footprint, briefly borrow a pool from their carrier thread during a pinned handoff, then own it independently so the virtual thread can still migrate while the arena is open.
The result is that the idiomatic, safe way to call native code — a confined arena per call — stops carrying an allocation tax, which removes a reason people had to reach for riskier shared or global arenas to avoid the cost.