109. Foreign Function & Memory API (FFM)
The Foreign Function & Memory (FFM) API replaces brittle JNI with safe off-heap memory management (Arena, MemorySegment) and direct native C library invocations.
Explanation
For decades, interfacing Java with native libraries (C/C++, GPU drivers, OpenSSL) required the Java Native Interface (JNI). JNI was notoriously complex: writing separate C bridge headers, compiling platform-specific .so/.dylib files, slow marshaling, and crash risks where bad pointers killed the JVM process.
JEP 454 (Java 22) finalized the Foreign Function & Memory (FFM) API (java.lang.foreign), offering two revolutionary capabilities: 1. Foreign Memory Access: MemorySegment and Arena allow allocating, manipulating, and releasing native off-heap memory safely. Arenas provide deterministic lifecycles (Arena.ofConfined() ensures instant memory deallocation when leaving a try-with-resources block), preventing off-heap memory leaks. 2. Foreign Function Invocation: Linker and SymbolLookup look up native C symbols dynamically (e.g. strlen, puts, BLAS math libraries) and invoke them directly from Java using strongly typed MethodHandle instances, with zero C boilerplate!
Example
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SymbolLookup;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
public class FfmNativeCall {
public static void main(String[] args) throws Throwable {
// 1. Deterministic off-heap memory allocation via Arena
try (Arena arena = Arena.ofConfined()) {
MemorySegment nativeString = arena.allocateFrom("Hello from FFM Native Memory!");
System.out.println("Native byte size: " + nativeString.byteSize());
System.out.println("String content: " + nativeString.getString(0));
// Memory is automatically and deterministically freed when leaving try block!
}
// 2. Call standard C library function 'strlen' directly
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MemorySegment strlenAddress = stdlib.find("strlen").orElseThrow();
// C signature: size_t strlen(const char *s)
FunctionDescriptor descriptor = FunctionDescriptor.of(
ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);
MethodHandle strlen = linker.downcallHandle(strlenAddress, descriptor);
try (Arena arena = Arena.ofConfined()) {
MemorySegment cStr = arena.allocateFrom("Modern Java 22 FFM");
long length = (long) strlen.invokeExact(cStr);
System.out.println("C strlen returned: " + length); // 18
}
}
}Sources
- https://openjdk.org/jeps/454 โ JEP 454: Foreign Function & Memory API (Java 22)
- https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/foreign/package-summary.html โ java.lang.foreign API