- 功能接口:
- 这是一个功能接口,因此可以用作lambda表达式或方法引用的赋值目标。
SymbolLookup
是Java平台的预览API。
符号查找是针对特定库(或多个库)创建的。随后,find(String)
方法接受符号的名称,并返回该库中符号的地址。
符号的地址被建模为零长度的内存段预览。该段可以以不同方式使用:
- 它可以传递给
Linker
预览,以创建一个downcall方法句柄,然后可以使用该句柄调用段地址处的外部函数。 - 它可以作为参数传递给现有的downcall方法句柄预览,作为底层外部函数的参数。
- 它可以存储预览在另一个内存段中。
- 它可以用于访问支持全局变量的内存区域(这需要首先调整大小预览段)。
获取符号查找
工厂方法libraryLookup(String, Arena)
和libraryLookup(Path, Arena)
为操作系统已知的库创建一个符号查找。库可以通过名称或路径指定。如果尚未加载库,则加载库。符号查找,也称为库查找,其生命周期由arena预览控制。例如,如果提供的arena是受限制的arena,则与符号查找关联的库在受限制的arena关闭预览时卸载:
try (Arena arena = Arena.ofConfined()) {
SymbolLookup libGL = SymbolLookup.libraryLookup("libGL.so", arena); // libGL.so在此处加载
MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
...
} // libGL.so在此处卸载
如果通过JNI之前加载了库,即通过System.load(String)
或System.loadLibrary(String)
,则该库也与特定类加载器关联。工厂方法loaderLookup()
为调用者的类加载器关联的所有库创建一个符号查找:
System.loadLibrary("GL"); // libGL.so在此处加载
...
SymbolLookup libGL = SymbolLookup.loaderLookup();
MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
System.load(String)
或
System.loadLibrary(String)
加载的库。加载器查找不公开通过创建库查找加载的库中的符号:
libraryLookup("libGL.so", arena).find("glGetString").isPresent(); // true
loaderLookup().find("glGetString").isPresent(); // false
L
的库查找公开
L
中的符号,即使
L
之前通过JNI加载(与类加载器的关联与库查找无关):
System.loadLibrary("GL"); // libGL.so在此处加载
libraryLookup("libGL.so", arena).find("glGetString").isPresent(); // true
最后,每个Linker
预览为操作系统和处理器组合支持的常用库提供一个符号查找。此符号查找,也称为默认查找,帮助客户快速找到众所周知符号的地址。例如,Linux/x64的Linker
预览可能选择通过默认查找公开libc
中的符号:
Linker nativeLinker = Linker.nativeLinker();
SymbolLookup stdlib = nativeLinker.defaultLookup();
MemorySegment malloc = stdlib.find("malloc").orElseThrow();
-
Method Summary
Modifier and TypeMethodDescription返回具有给定名称的符号的地址。static SymbolLookupPREVIEW
libraryLookup
(String name, ArenaPREVIEW arena) 加载具有给定名称的库(如果尚未加载),并为该库中的符号创建一个符号查找。static SymbolLookupPREVIEW
libraryLookup
(Path path, ArenaPREVIEW arena) 从给定路径加载库(如果尚未加载),并为该库中的符号创建一个符号查找。static SymbolLookupPREVIEW
返回与调用者的类加载器关联的库中符号的符号查找。default SymbolLookupPREVIEW
or
(SymbolLookupPREVIEW other) 返回一个组合符号查找,如果找到此查找中的符号,则返回该查找的结果,否则返回另一个查找中的符号的结果。
-
Method Details
-
find
返回具有给定名称的符号的地址。- 参数:
-
name
- 符号名称。 - 返回:
- 如果找到,则返回一个指示符号地址的零长度内存段。
-
or
返回一个组合符号查找,如果找到此查找中的符号,则返回该查找的结果,否则返回另一个查找中的符号的结果。- API注释:
-
此方法可用于链接多个符号查找,例如,以便按顺序从多个库中检索符号:
var lookup = SymbolLookup.libraryLookup("foo", arena) .or(SymbolLookup.libraryLookup("bar", arena)) .or(SymbolLookup.loaderLookup());
- 参数:
-
other
- 应用于查找此查找中未找到的符号的符号查找。 - 返回:
- 一个组合符号查找,如果找到此查找中的符号,则返回该查找的结果,否则返回另一个查找的结果。
-
loaderLookup
返回与调用者的类加载器关联的库中符号的查找。当库通过调用
System.load(String)
或System.loadLibrary(String)
从由CL
定义的类中的代码加载时,库与类加载器CL
关联。如果该代码进一步调用System.load(String)
或System.loadLibrary(String)
,则会加载更多库并与CL
关联。此方法返回的符号查找始终是当前的:它反映了与相关类加载器关联的所有库,即使它们是在此方法返回后加载的。与类加载器关联的库在类加载器变得不可达时被卸载。此方法返回的符号查找与一个新的scopePREVIEW关联,该scope使调用者的类加载器保持可达。因此,与调用者的类加载器关联的库将保持加载(及其符号可用),只要对该类加载器的加载器查找或其获取的任何段之一是可达的。
在从堆栈上没有调用者帧的上下文中调用此方法的情况下(例如,直接从JNI附加的线程中调用时),调用者的类加载器默认为系统类加载器。
- 返回:
- 与调用者的类加载器关联的库中符号的查找。
- 参见:
-
libraryLookup
加载具有给定名称的库(如果尚未加载)并为该库中的符号创建符号查找。返回的库查找的生命周期由提供的arena控制。例如,如果提供的arena是受限制的arena,则与返回的查找关联的库将在提供的受限制的arena被关闭PREVIEW时卸载。此方法是受限制的。受限制的方法是不安全的,如果使用不正确,可能会导致JVM崩溃,或者更糟糕的是,悄无声息地导致内存损坏。因此,客户端应避免依赖受限制的方法,尽可能使用安全和受支持的功能。
- 实现注意:
-
解析库名称的过程是特定于操作系统的。例如,在符合POSIX的操作系统中,库名称根据该操作系统的
dlopen
函数的规范解析。在Windows中,库名称根据LoadLibrary
函数的规范解析。 - 参数:
-
name
- 库中应查找符号的名称。 -
arena
- 从返回的查找中获取的符号与之关联的arena。 - 返回:
- 适合在具有给定名称的库中查找符号的新符号查找。
- 抛出:
-
IllegalStateException
- 如果arena.scope().isAlive() == false
-
WrongThreadException
- 如果arena
是受限制的arena,并且从线程T
调用此方法,而不是arena的所有者线程。 -
IllegalArgumentException
- 如果name
未标识有效的库。 -
IllegalCallerException
- 如果调用者位于未启用本机访问的模块中。
-
libraryLookup
从给定路径加载库(如果尚未加载)并为该库中的符号创建符号查找。返回的库查找的生命周期由提供的arena控制。例如,如果提供的arena是受限制的arena,则与返回的查找关联的库将在提供的受限制的arena被关闭PREVIEW时卸载。此方法是受限制的。受限制的方法是不安全的,如果使用不正确,可能会导致JVM崩溃,或者更糟糕的是,悄无声息地导致内存损坏。因此,客户端应避免依赖受限制的方法,尽可能使用安全和受支持的功能。
- 实现注意:
-
在Linux上,此工厂方法提供的功能以及返回的符号查找是使用
dlopen
、dlsym
和dlclose
函数实现的。 - 参数:
-
path
- 库中应查找符号的路径。 -
arena
- 从返回的查找中获取的符号与之关联的arena。 - 返回:
- 适合在具有给定路径的库中查找符号的新符号查找。
- 抛出:
-
IllegalStateException
- 如果arena.scope().isAlive() == false
-
WrongThreadException
- 如果arena
是受限制的arena,并且从线程T
调用此方法,而不是arena的所有者线程。 -
IllegalArgumentException
- 如果path
未指向有效的库。 -
IllegalCallerException
- 如果调用者位于未启用本机访问的模块中。
-
SymbolLookup
。