Native Image 构建配置

Native Image 支持多种选项来配置 native-image 构建器。

目录 #

嵌入配置文件 #

我们建议您通过将 native-image.properties 文件嵌入到项目 JAR 文件中,来为 native-image 构建器提供配置。native-image 构建器还将自动获取 META-INF/native-image/ 目录(或其任何子目录)中提供的所有配置选项,并使用它们来构建 native-image 命令行选项。

为避免项目组成部分使用重叠配置进行构建的情况,我们建议您在 META-INF/native-image 中使用子目录:由多个 Maven 项目构建的 JAR 文件不会受到重叠 native-image 配置的影响。例如:

  • foo.jar 的配置位于 META-INF/native-image/foo_groupID/foo_artifactID
  • bar.jar 的配置位于 META-INF/native-image/bar_groupID/bar_artifactID

包含 foobar 的 JAR 文件将包含这两种配置,而不会发生冲突。因此,推荐的在 JAR 文件中存储配置数据的布局如下:

META-INF/
└── native-image
    └── groupID
        └── artifactID
            └── native-image.properties

请注意,在 native-image.properties 文件中使用 ${.} 会扩展到包含该精确配置文件的资源位置。如果 native-image.properties 文件引用其子目录中的资源,这会很有用,例如 -H:ResourceConfigurationResources=${.}/custom_resources.json。请始终确保使用接受资源的选项变体,即使用 -H:ResourceConfigurationResources 而不是 -H:ResourceConfigurationFiles。在此上下文中有效的其他选项包括:

  • -H:DynamicProxyConfigurationResources
  • -H:JNIConfigurationResources
  • -H:ReflectionConfigurationResources
  • -H:ResourceConfigurationResources
  • -H:SerializationConfigurationResources

通过拥有这样一个可组合的 native-image.properties 文件,构建原生可执行文件不需要任何额外的命令行选项。只需运行以下命令即可:

$JAVA_HOME/bin/native-image -jar target/<name>.jar

要确定在构建原生可执行文件时应用了哪个配置,请使用 native-image --verbose。这会显示 native-image 从何处获取配置,以构建用于原生镜像构建器的最终复合配置命令行选项。

native-image --verbose -jar build/basic-app-0.1-all.jar
Apply jar:file://~/build/basic-app-0.1-all.jar!/META-INF/native-image/io.netty/common/native-image.properties
Apply jar:file://~/build/basic-app-0.1-all.jar!/META-INF/native-image/io.netty/buffer/native-image.properties
Apply jar:file://~/build/basic-app-0.1-all.jar!/META-INF/native-image/io.netty/transport/native-image.properties
Apply jar:file://~/build/basic-app-0.1-all.jar!/META-INF/native-image/io.netty/handler/native-image.properties
Apply jar:file://~/build/basic-app-0.1-all.jar!/META-INF/native-image/io.netty/codec-http/native-image.properties
...
Executing [
    <composite configuration command line options for the image builder>
]

使用 META-INF/native-image 中配置的典型示例可以在Native Image 配置示例中找到。

配置文件格式 #

native-image.properties 文件是一个 Java 属性文件,用于指定 native-image 的配置。支持以下属性。

Args

如果您的项目需要自定义 native-image 命令行选项才能正确构建,请使用此属性。例如,native-image-configure-examples/configure-at-runtime-examplenative-image.properties 文件包含 Args = --initialize-at-build-time=com.fasterxml.jackson.annotation.JsonProperty$Access,以确保类 com.fasterxml.jackson.annotation.JsonProperty$Access 在可执行文件构建时初始化。

JavaArgs

有时可能需要为运行 native-image 构建器的 JVM 提供自定义选项。在这种情况下,请使用 JavaArgs 属性。

ImageName

此属性指定可执行文件的用户定义名称。如果未使用 ImageName,则会自动选择一个名称:* native-image -jar <name.jar> 的默认可执行文件名为 <name> * native-image -cp ... fully.qualified.MainClass 的默认可执行文件名为 fully.qualified.mainclass

请注意,使用 ImageName 并不会阻止您通过命令行覆盖名称。例如,如果 foo.bar 包含 ImageName=foo_app:* native-image -jar foo.bar 生成可执行文件 foo_app,但 * native-image -jar foo.bar application 生成可执行文件 application

更改默认配置目录 #

Native Image 默认将配置信息存储在用户主目录中:$HOME/.native-image/。要更改此默认值,请将环境变量 NATIVE_IMAGE_USER_HOME 设置为其他位置。例如:

export NATIVE_IMAGE_USER_HOME= $HOME/.local/share/native-image

参数评估顺序 #

传递给 native-image 的选项从左到右评估。这也适用于通过 META-INF/native-image 目录中的配置文件间接传递的选项。考虑以下示例:有一个 JAR 文件包含 native-image.properties,其中包含 Args = -H:Optimize=0。您可以通过在 -cp <jar-file> 之后使用 -H:Optimize=2 选项来覆盖 JAR 文件中包含的设置。

Native Image 构建的内存配置 #

native-image 构建器在 JVM 上运行,并使用底层平台的内存管理。适用于 native-image 构建器的是通常的 Java 命令行垃圾回收选项。

在创建原生可执行文件期间,会创建整个应用程序的表示形式,以确定哪些类和方法将在运行时使用。这是一个计算密集型过程,使用以下内存使用默认值:

-Xss10M \
-XX:MaxRAMPercentage=<percentage based on available memory> \
-XX:GCTimeRatio=19 \
-XX:+ExitOnOutOfMemoryError \

可以通过将 -J + <jvm option for memory> 传递给 native-image 工具来更改这些默认值。

-XX:MaxRAMPercentage 值决定了构建器的最大堆大小,并根据系统的可用内存计算得出。默认情况下,它最大限制为 32GB,可以通过例如 -J-XX:MaxRAMPercentage=90.0(表示物理内存的 90%)或 -Xmx4g(表示 4GB)来覆盖。-XX:GCTimeRatio=19 将垃圾回收总时间的目标增加到 5%,这更注重吞吐量并减少峰值 RSS。构建过程也会在第一个 OutOfMemoryError-XX:+ExitOnOutOfMemoryError)时退出,以便在内存压力很大的环境中提供更快的反馈。

默认情况下,native-image 工具最多使用 32 个线程(但不超过可用处理器数量)。对于自定义值,请使用 --parallelism=... 选项。

有关 native-image 工具可用的其他相关选项,请参阅命令 native-image --expert-options-all 的输出。

指定构建时需要定义的类型 #

构建原生二进制文件时,结构良好的库或应用程序应自行处理 Java 类型链接(确保所有可达的 Java 类型在构建时完全定义)。默认行为是在运行时抛出链接错误(如果发生)。但是,您可以通过指定哪些类需要在构建时完全链接来防止不必要的链接错误。为此,请使用 --link-at-build-time 选项。如果该选项在正确的上下文中使用(见下文),您可以指定在构建时需要链接的类,而无需明确列出类和包。它的设计方式是,库只能配置自己的类,以避免对其他库产生任何副作用。您可以在命令行上将该选项传递给 native-image 工具,或者将其嵌入到模块路径或类路径上的 native-image.properties 文件中。

根据选项的使用方式和位置,它的行为会有所不同:

  • 如果使用不带参数的 --link-at-build-time,则作用域中的所有类都必须完全定义。如果在命令行上不带参数使用,所有类都将被视为“构建时链接”类。如果在模块路径上不带参数嵌入到 native-image.properties 文件中,则模块的所有类都将被视为“构建时链接”类。如果将 --link-at-build-time 嵌入到类路径上的 native-image.properties 文件中,则会抛出以下错误:
      Error: Using '--link-at-build-time' without args only allowed on module path. 'META-INF/native-image/org.mylibrary/native-image.properties' in 'file:///home/test/myapp/MyLibrary.jar' not part of module path.
    
  • 如果使用带参数的 --link-at-build-time 选项,例如 --link-at-build-time=foo.bar.Foobar,demo.myLibrary.Name,...,则参数应为完全限定的类名或包名。当在模块路径或类路径上使用时(嵌入在 native-image.properties 文件中),只能指定在同一 JAR 文件中定义的类和包。类路径上使用的库的包需要明确列出。为了简化此过程,请使用 @<prop-values-file> 语法自动在单独的文件中生成包列表(或类列表)。

另一个方便的选项是 --link-at-build-time-paths,它允许通过其他方式指定哪些类需要在构建时完全定义。此变体需要与通过 -p (--module-path) 或 -cp (--class-path) 传递的参数类型相同的参数:

--link-at-build-time-paths <class search path of directories and ZIP/JAR files>

给定的条目将被搜索,并且其中的所有类都将注册为 --link-at-build-time 类。此选项只允许在命令行上使用。

联系我们