外部函数与内存API(FFM)- ERR404博客

作者:API传播员 · 2025-10-31 · 阅读时间:5分钟

随着JDK 22和JEP 424的发布,Java引入了一个全新的特性:外部函数与内存API(Foreign Function and Memory API,简称 FFM)。本文将详细介绍该API的设计初衷、核心组件以及使用方法,帮助开发者更好地理解和应用这一技术。


外部函数与内存API的设计初衷

Java平台提供了丰富的工具、库和驱动(如JDBC、HTTP、NIO、套接字等),但在某些场景下,开发者仍需与JVM之外的资源进行交互。FFM API的诞生正是为了解决这一问题,它通过高效调用外部函数和安全访问外部内存,使Java程序能够与原生库和数据进行互操作,同时避免了JNI(Java Native Interface)的复杂性和潜在风险。

FFM API主要位于java.base模块的java.lang.foreign包中。通过该API,开发者可以分配、访问和管理外部内存,从而实现与JVM外部资源的通信。


核心组件概览

FFM API的核心组件包括以下几个部分:

  • MemorySegment:表示一段连续的内存区域。
  • MemoryAddress:提供指向内存段中特定位置的指针。
  • SegmentAllocator:用于分配具有特定特征(如大小和对齐方式)的内存段。
  • LinkerFunctionDescriptorSymbolLookup:用于调用外部函数。

这些组件共同构成了FFM API的基础,开发者可以利用它们高效、安全地操作外部内存和调用外部函数。


使用指南

链接器(Linker)

链接器是实现Java程序与JVM外部通信的核心组件。开发者通常使用针对操作系统和处理器架构优化的nativeLinker()方法,以确保与原生库和函数交互时的兼容性和效率。如果项目有特殊需求,也可以选择第三方原生链接器,但需综合考虑以下因素:

  • 平台兼容性
  • 性能
  • 易用性
  • 社区支持
  • 可靠性

从原生库查找符号

符号是指需要从Java代码访问的外部库中定义的函数或变量。实现步骤如下:

  1. 获取一个或多个库中符号的地址。
  2. 通过FunctionDescriptor接口指定待调用函数的签名和调用约定,包括参数类型、返回类型等特征。
  3. 获取符号地址并定义描述符后,使用MethodHandles API将其转换为MethodHandle

以下是一个示例:将接收两个整数参数并返回double类型的函数转换为MethodHandle,以便在Java代码中调用。

// 定义参数类型和返回类型
FunctionDescriptor descriptor = FunctionDescriptor.of(CLinker.C_DOUBLE, CLinker.C_INT, CLinker.C_INT);
MethodHandle handle = linker.downcallHandle(symbol, descriptor);

分配内存区域

在与需要手动内存管理的外部库交互时,FFM允许开发者在Java堆外分配和管理内存。这种方式确保底层函数能够读取参数,因为Java运行时中可能不存在必要的内存空间。

需要注意的是,实际开发中存储的通常是数据指针而非数据本身。例如,在处理链表等复杂数据结构时,开发者需要逐个分配列表项的内存,这可能会显得繁琐。

调用外部函数

通过包含参数的内存区域调用外部函数。借助MethodHandle,开发者可以轻松实现函数调用。例如,假设外部库中定义了一个接收两个整数参数并返回double的函数myFunction,可以通过以下方式调用:

double result = (double) handle.invokeExact(10, 20);

读取堆内存区域结果

对于像radixsort这样直接修改输入数据且无返回值的函数,需要在同一内存区域重新读取数据。以下是一个示例:

MemorySegment segment = MemorySegment.allocateNative(100);
radixsort(segment);
byte[] result = segment.toArray(ValueLayout.JAVA_BYTE);

FFM API的优势

FFM相比传统的JNI具有以下显著优势:

  • 模板代码更少:减少了重复性代码的编写。
  • API更简洁:提高了代码的可读性和维护性。
  • 内存管理更轻量:开发者可以更高效地管理堆外内存。
  • 类型安全:避免了JNI中常见的类型转换错误。

实际应用与反馈

目前,FFM API已在多个项目中得到了测试和应用。例如,RocksDB团队在测试FFM时发现,它在性能提升、代码精简和互操作性增强方面表现突出,为增强RocksDB的Java API及开拓新机遇提供了可靠的技术支持。

更多关于RocksDB团队的测试反馈,请参考:RocksDB博客


总结

外部函数与内存API(FFM)为Java开发者提供了一个高效、安全的工具,用于与JVM外部资源进行交互。通过FFM,开发者可以更轻松地调用原生库、管理外部内存,并避免JNI的复杂性和风险。

希望本文对您了解FFM及其应用有所帮助。如有任何问题或建议,欢迎交流!更多关于JRE和内存区域的深入探讨,敬请期待后续内容。


原文链接: https://sebastienallemand.fr/posts/jep424-ffm/