模块 java.base

接口 SymbolLookup

函数接口:
这是一个功能接口,因此可以用作 lambda 表达式或方法引用的赋值目标。

@FunctionalInterface public interface SymbolLookup
SymbolLookup 是 Java 平台的预览 API。
程序只能在启用预览功能时使用 SymbolLookup
预览功能可能会在未来的版本中删除,或升级为 Java 平台的永久功能。
symbol lookup 检索一个或多个库中符号的地址。符号是命名实体,例如函数或全局变量。

符号查找是针对特定库(或多个库)创建的。随后,find(String) 方法获取一个符号的名称并返回该符号在该库中的地址。

符号的地址被建模为零长度内存段PREVIEW .该段可以以不同的方式使用:

  • 它可以传递给Linker PREVIEW 创建一个 downcall 方法句柄,然后可以使用它来调用段地址处的外部函数。
  • 它可以传递给现有的向下调用方法句柄PREVIEW ,作为底层外部函数的参数。
  • 它可以是存储PREVIEW 在另一个内存段内。
  • 它可用于访问支持全局变量的内存区域(这可能需要resizing PREVIEW 首先是段)。

获取符号查找

工厂方法 libraryLookup(String, SegmentScope) libraryLookup(Path, SegmentScope) 为操作系统已知的库创建符号查找。该库由其名称或路径指定。如果尚未加载该库,则会加载该库。称为 library lookup 的符号查找与 scope 相关联PREVIEW ;当范围变得不是SegmentScope.isAlive() PREVIEW ,库被卸载:
 try (Arena arena = Arena.openConfined()) {
   SymbolLookup libGL = SymbolLookup.libraryLookup("libGL.so", arena.scope()); // libGL.so loaded here
   MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
   ...
 } // libGL.so unloaded here
 

如果库之前是通过 JNI 加载的,即通过 System.load(String) System.loadLibrary(String) ,那么该库也与特定的类加载器相关联。工厂方法 loaderLookup() 为与调用者的类加载器关联的所有库创建符号查找:

System.loadLibrary("GL"); // libGL.so loaded here
...
SymbolLookup libGL = SymbolLookup.loaderLookup();
MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
 
此符号查找称为 loader lookup,对于与类加载器关联的库而言是动态的。如果其他库随后通过 JNI 加载并与类加载器相关联,则加载器查找将自动公开它们的符号。

请注意,加载程序查找仅公开先前通过 JNI 加载的库中的符号,即通过 System.load(String) System.loadLibrary(String) 加载。加载程序查找不会公开在创建库查找过程中加载的库中的符号:

 libraryLookup("libGL.so", scope).find("glGetString").isPresent(); // true
 loaderLookup().find("glGetString").isPresent(); // false
 
另请注意,库 L 的库查找会在 L 中公开符号,即使 L 先前已通过 JNI 加载(与类加载器的关联对库查找无关紧要):
 System.loadLibrary("GL"); // libGL.so loaded here
 libraryLookup("libGL.so", scope).find("glGetString").isPresent(); // true
 

最后,每个Linker PREVIEW Linker 支持的操作系统和处理器组合上常用的库提供符号查找PREVIEW .这种称为 default lookup 的符号查找可帮助客户端快速找到知名符号的地址。例如,一个Linker PREVIEW 对于 Linux/x64,可能会选择通过默认查找在 libc 中公开符号:

 Linker nativeLinker = Linker.nativeLinker();
 SymbolLookup stdlib = nativeLinker.defaultLookup();
 MemorySegment malloc = stdlib.find("malloc").orElseThrow();
 
  • 方法详情

    • find

      返回具有给定名称的符号的地址。
      参数:
      name - 交易品种名称。
      返回:
      一个零长度的内存段,其地址指示符号的地址(如果找到)。
    • loaderLookup

      static SymbolLookup PREVIEW  loaderLookup()
      返回与调用者的类加载器关联的库中符号的符号查找。

      当通过调用 System.load(String) System.loadLibrary(String) CL 定义的类中的代码加载库时,库与类加载器 CL 相关联。如果该代码进一步调用 System.load(String) System.loadLibrary(String) ,则会加载更多库并与 CL 关联。此方法返回的符号查找始终是最新的:它反映了与相关类加载器关联的所有库,即使它们是在此方法返回之后加载的。

      当类加载器变为 遥不可及 时,与类加载器关联的库将被卸载。此方法返回的符号查找由始终处于活动状态并保持调用者的类加载器可访问的作用域支持。因此,与调用者的类加载器关联的库将保持加载(并且它们的符号可用),只要可以访问该类加载器的加载器查找。

      如果从堆栈上没有调用者框架的上下文调用此方法(例如,当直接从 JNI 附加线程调用时),调用者的类加载器默认为 系统类加载器

      返回:
      在与调用者的类加载器关联的库中查找符号。
      参见:
    • libraryLookup

      static SymbolLookup PREVIEW  libraryLookup(String  name, SegmentScope PREVIEW  scope)
      加载具有给定名称的库(如果尚未加载)并为该库中的符号创建符号查找。当提供的作用域变为不时,库将被卸载PREVIEW ,如果没有其他库查找仍在使用它。
      实现注意事项:
      解析库名称的过程是特定于操作系统的。例如,在符合 POSIX 标准的操作系统中,库名称根据该操作系统的 dlopen 函数规范进行解析。在 Windows 中,库名称根据 LoadLibrary 函数的规范进行解析。

      这个方法是restricted 。受限方法是不安全的,如果使用不当,它们的使用可能会使 JVM 崩溃,或者更糟的是,无声地导致内存损坏。因此,客户应避免依赖受限的方法,并尽可能使用安全和受支持的功能。

      参数:
      name - 应在其中查找符号的库的名称。
      scope - 与从返回的查找中获得的符号关联的范围。
      返回:
      一个新的符号查找适用于在具有给定名称的库中查找符号。
      抛出:
      IllegalArgumentException - 如果 name 未识别有效库。
      IllegalCallerException - 如果调用者所在的模块未启用本机访问。
    • libraryLookup

      static SymbolLookup PREVIEW  libraryLookup(Path  path, SegmentScope PREVIEW  scope)
      从给定路径加载库(如果尚未加载)并为该库中的符号创建符号查找。当提供的作用域变为不时,库将被卸载PREVIEW ,如果没有其他库查找仍在使用它。

      这个方法是restricted 。受限方法是不安全的,如果使用不当,它们的使用可能会使 JVM 崩溃,或者更糟的是,无声地导致内存损坏。因此,客户应避免依赖受限的方法,并尽可能使用安全和受支持的功能。

      实现注意事项:
      在 Linux 上,此工厂方法提供的功能和返回的符号查找是使用 dlopendlsymdlclose 函数实现的。
      参数:
      path - 应在其中查找符号的库的路径。
      scope - 与从返回的查找中获得的符号关联的范围。
      返回:
      适合在具有给定路径的库中查找符号的新符号查找。
      抛出:
      IllegalArgumentException - 如果 path 没有指向有效的库。
      IllegalCallerException - 如果调用者所在的模块未启用本机访问。