🔍 什么是 FFM API?
Foreign Function & Memory API(FFM API) 是 Java 提供的一套用于访问非 Java 内存(如 C 库分配的内存)以及调用原生函数的标准化接口。
🛠️ 步骤一:最简单的内存访问示例
import java.nio.ByteOrder;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ValueLayout;
public class MemoryAccessDemo {
public static void main(String[] args) {
// 分配 4 字节堆外内存
try (MemorySegment segment = MemorySegment.allocateNative(4)) {
// 写入整型值
segment.set(ValueLayout.JAVA_INT, 0, 0x12345678);
// 读取整型值
int value = segment.get(ValueLayout.JAVA_INT, 0);
System.out.printf("读取到的值为: 0x%X%n", value);
}
}
}
输出:
读取到的值为: 0x12345678
📌 注意:使用完 MemorySegment
后应关闭以释放资源,推荐使用 try-with-resources。
🧪 步骤二:调用 C 标准库函数(如 strlen)
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.Linker;
import jdk.incubator.foreign.MemorySegment;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
public class CLibraryDemo {
public static void main(String[] args) throws Throwable {
// 获取系统链接器
Linker linker = Linker.nativeLinker();
CLinker cLinker = CLinker.getInstance();
// 获取 strlen 函数句柄
MethodHandle strlen = linker.downcallHandle(
linker.defaultLookup().lookup("strlen").get(),
FunctionDescriptor.of(cLinker.C_LONG, cLinker.C_POINTER)
);
// 创建字符串内存段
MemorySegment str = cLinker.toCString("Hello FFM API!");
// 调用 strlen
long length = (long) strlen.invokeExact(str.address());
System.out.println("字符串长度:" + length);
}
}
输出:
字符串长度:14
🧩 步骤三:调用自定义 C 动态库函数
1. 编写 C 代码(libdemo.c)
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
2. 编译为动态库(Linux/macOS)
gcc -shared -o libdemo.so libdemo.c
3. Java 调用该函数
// Java 代码略(详见完整工程)
🧨 步骤四:描述 C 结构体(Struct)布局
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.SequenceLayout;
import jdk.incubator.foreign.ValueLayout;
public class StructDemo {
public static void main(String[] args) {
// 定义 struct Point { int x; int y; }
MemoryLayout structLayout = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
);
// 分配内存
try (MemorySegment point = MemorySegment.allocateNative(structLayout)) {
// 设置 x=10, y=20
point.set(ValueLayout.JAVA_INT, 0, 10);
point.set(ValueLayout.JAVA_INT, 4, 20);
// 读取 x, y
int x = point.get(ValueLayout.JAVA_INT, 0);
int y = point.get(ValueLayout.JAVA_INT, 4);
System.out.println("Point(x=" + x + ", y=" + y + ")");
}
}
}
输出:
Point(x=10, y=20)