实验性代理选项

native-image-agent 工具有一些当前处于实验阶段的选项,这些选项可能会在将来的版本中启用,但也可能发生更改或完全删除。这些选项将在本文档中介绍。

对预定义类的支持 #

Native-image 需要在映像构建时知道所有类(“封闭世界假设”)。但是,Java 支持在运行时加载新类。为了模拟类加载,可以告诉代理跟踪动态加载的类并保存其字节码,以便映像构建器在以后使用。可以通过将 experimental-class-define-support 添加到代理选项字符串来启用此功能,例如:-agentlib:native-image-agent=config-output-dir=config,experimental-class-define-support 除了标准配置文件外,代理还会在配置输出目录中创建一个名为 agent-extracted-predefined-classes 的目录,并动态写入新加载类的字节码。然后,映像构建器可以使用配置目录,无需进行任何其他调整。这些类将在映像构建期间加载,但不会初始化或提供给应用程序。在运行时,如果尝试加载与跟踪期间遇到的类之一具有相同名称和字节码的类,则预定义类将提供给应用程序。

已知限制 #

  • Native 映像仅支持在每次执行中“加载”一次预定义类,并且仅由一个类加载器加载。
  • 预定义类在运行时“加载”时初始化,不能在构建时初始化。
  • 代理收集所有未由 Java VM 的内置类加载器(除了一些例外)加载的类,即来自类路径或模块路径的类。这包括由任何自定义类加载器加载的类。
  • 名称或字节码中包含不同数据的类(例如,顺序或随机数或时间戳)通常无法在运行时与预定义类匹配。在这种情况下,需要调整生成此类类的方式。

打印带有来源的配置 #

为了调试,了解某些配置项的来源可能很有用。通过将 experimental-configuration-with-origins 添加到代理选项字符串,代理将以树状形式输出配置项分解到其源自的调用上下文(堆栈跟踪)的配置文件。此选项应与 config-output-dir=<path> 结合使用,以告诉代理将配置文件输出到哪里。代理选项字符串示例:-agentlib:native-image-agent=config-output-dir=config-with-origins/,experimental-configuration-with-origins

从代理的输出中省略配置 #

代理可以省略存在于现有配置文件中的跟踪配置项。有两种方法可以指定这些现有配置文件

  • 使用来自类路径或模块路径的配置文件。当将 experimental-omit-config-from-classpath 添加到代理选项字符串时,运行应用程序的类路径和模块路径将扫描 META-INF/native-image/**/*.json 配置文件。
  • 通过使用 config-to-omit=<path> 明确地指向代理指向现有的配置目录。

使用代理生成条件配置 #

代理可以使用启发式方法生成对用户指定类具有可达性条件的配置。代理将跟踪配置来源并尝试自动推断条件。用户类是通过代理过滤器文件指定的(有关格式的更多信息,请参阅 有关代理的更多信息)。此外,生成的配置可以使用另一个过滤器文件进行进一步过滤。

目前,此功能支持两种模式

  1. 使用代理在一次运行中生成条件配置。
  2. 从代理的多次运行生成条件配置,最后合并收集到的数据。

在代理运行期间生成条件配置 #

要启用此模式,请将 experimental-conditional-config-filter-file=<path> 添加到代理的命令行,其中 <path> 指向代理过滤器文件。被此过滤器视为包含的类将被指定为用户代码类。要进一步过滤生成的配置,可以使用 conditional-config-class-filter-file=<path>,其中 <path> 是指向代理过滤器文件的路径。

从多个代理运行生成条件配置 #

条件配置可以从到达应用程序中不同代码路径的多个代理运行生成。每个代理运行都会生成包含元数据的配置。native-image-configure 然后用于合并收集到的数据并生成条件配置。要在这种模式下运行代理,请将 experimental-conditional-config-part 添加到代理的命令行。所有代理运行完成后,您可以通过调用以下命令生成条件配置

native-image-configure generate-conditional --user-code-filter=<path-to-filter-file> --class-name-filter=<path-to-filter-file> --input-dir=<path-to-agent-run-output-1> --input-dir=<path-to-agent-run-ouput-2> ... --output-dir=<path-to-resulting-conditional-config>

其中

  • --user-code-filter=<path-to-filter-file>:指向指定用户类的代理过滤器文件的路径
  • (可选)--class-name-filter=<path-to-filter-file>:指向进一步过滤生成的配置的代理过滤器文件的路径

底层启发式方法 #

条件是使用应用程序的调用树生成的。启发式方法的工作原理如下

  1. 对于每个唯一方法,创建一个包含对应于该方法的调用树中所有节点的列表
  2. 对于每个唯一方法,如果该方法在树中具有多个调用节点
    • 查找该方法所有调用节点的通用配置
    • 对于该方法的每个调用节点,将这些调用中不常见的配置传播到调用者节点
  3. 重复步骤 2. 直到某个迭代在调用树中没有产生更改。
  4. 对于包含配置的每个节点,使用该方法的类作为条件生成条件配置项。

这种启发式方法的主要目标是尝试找出方法根据调用者创建不同配置项的位置(例如,包装 Class.forName 调用的方法)。这意味着启发式方法不适用于通过其他依赖项生成配置的代码(例如,相同的方法返回通过不同的系统属性调用 Class.forName 的调用)。

进一步阅读 #

与我们联系