原生镜像中的外部函数和内存 API

外部函数和内存 (FFM) API 是一种接口,它使 Java 代码能够与原生代码交互,反之亦然。它在 JDK 22 中通过 JEP 454 最终确定。目前,在 Native Image 中的支持是实验性的,并且必须通过 -H:+ForeignAPISupport(以及 -H:+UnlockExperimentalVMOptions)明确启用。允许执行“受限”原生操作(包括创建用于调用或被原生代码调用的句柄)的模块必须使用 --enable-native-access= 选项指定。本页面概述了 Native Image 中 FFM API 的支持情况。

外部内存 #

外部内存功能通常受支持。共享竞技场目前不受支持。

外部函数 #

FFM API 使 Java 代码能够 *向下* 调用原生函数,反之,也允许原生代码 *向上* 通过方法句柄调用 Java 代码。这两种调用分别称为“下调 (downcalls)”和“上调 (upcalls)”,统称为“外部调用 (foreign calls)”。

注意:目前,外部调用在 x64 架构上受支持。具体来说,下调在 x64 Linux、Windows 和 MacOS 上受支持,而上调仅在 x64 Linux 上受支持。

查找原生函数 #

FFM API 提供了 SymbolLookup 接口,用于按名称在原生库中查找函数。SymbolLookup.loaderLookup() 是目前唯一受支持的 SymbolLookup 类型。

注册外部调用 #

为了在运行时对原生代码进行调用,必须在镜像构建时生成支持代码。因此,必须向 native-image 工具提供描述符,这些描述符描述了可在运行时执行下调的函数。

这些描述符可以使用自定义 Feature 进行注册,例如

import static java.lang.foreign.ValueLayout.*;

class ForeignRegistrationFeature implements Feature { 
  public void duringSetup(DuringSetupAccess access) {
    RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid());
    RuntimeForeignAccess.registerForUpcall(FunctionDescriptor.ofVoid());
    RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid(), Linker.Option.critical(false));
    RuntimeForeignAccess.registerForUpcall(FunctionDescriptor.of(JAVA_INT, JAVA_INT));
    RuntimeForeignAccess.registerForUpcall(FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT));
    RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(ADDRESS, JAVA_INT, JAVA_INT), Linker.Option.firstVariadicArg(1));
    RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid(JAVA_INT), Linker.Option.captureCallState("errno"));
  }
}

要激活自定义功能,请将 --features=com.example.ForeignRegistrationFeature 选项(功能类的完全限定名)传递给 native-image。建议 通过 *native-image.properties* 文件 来实现。

联系我们