0
点赞
收藏
分享

微信扫一扫

Java Foreign Function & Memory API

绣文字 07-14 06:00 阅读 15

🔍 什么是 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)

举报

相关推荐

0 条评论