原生镜像构建输出
在这里,您将找到有关 GraalVM 原生镜像构建输出的信息。以下是构建 HelloWorld
类的原生可执行文件的示例输出
================================================================================
GraalVM Native Image: Generating 'helloworld' (executable)...
================================================================================
[1/8] Initializing... (2.8s @ 0.15GB)
Java version: 20+34, vendor version: GraalVM CE 20-dev+34.1
Graal compiler: optimization level: 2, target machine: x86-64-v3
C compiler: gcc (linux, x86_64, 12.2.0)
Garbage collector: Serial GC (max heap size: 80% of RAM)
--------------------------------------------------------------------------------
Build resources:
- 13.24GB of memory (42.7% of 31.00GB system memory, determined at start)
- 16 thread(s) (100.0% of 16 available processor(s), determined at start)
[2/8] Performing analysis... [****] (4.5s @ 0.54GB)
3,163 reachable types (72.5% of 4,364 total)
3,801 reachable fields (50.3% of 7,553 total)
15,183 reachable methods (45.5% of 33,405 total)
957 types, 81 fields, and 480 methods registered for reflection
57 types, 55 fields, and 52 methods registered for JNI access
4 native libraries: dl, pthread, rt, z
[3/8] Building universe... (0.8s @ 0.99GB)
[4/8] Parsing methods... [*] (0.6s @ 0.75GB)
[5/8] Inlining methods... [***] (0.3s @ 0.32GB)
[6/8] Compiling methods... [**] (3.7s @ 0.60GB)
[7/8] Laying out methods... [*] (0.8s @ 0.83GB)
[8/8] Creating image... [**] (3.1s @ 0.58GB)
5.32MB (24.22%) for code area: 8,702 compilation units
7.03MB (32.02%) for image heap: 93,301 objects and 5 resources
8.96MB (40.83%) for debug info generated in 1.0s
659.13kB ( 2.93%) for other data
21.96MB in total
--------------------------------------------------------------------------------
Top 10 origins of code area: Top 10 object types in image heap:
4.03MB java.base 1.14MB byte[] for code metadata
927.05kB svm.jar (Native Image) 927.31kB java.lang.String
111.71kB java.logging 839.68kB byte[] for general heap data
63.38kB org.graalvm.nativeimage.base 736.91kB java.lang.Class
47.59kB jdk.proxy1 713.13kB byte[] for java.lang.String
35.85kB jdk.proxy3 272.85kB c.o.s.c.h.DynamicHubCompanion
27.06kB jdk.internal.vm.ci 250.83kB java.util.HashMap$Node
23.44kB org.graalvm.sdk 196.52kB java.lang.Object[]
11.42kB jdk.proxy2 182.77kB java.lang.String[]
8.07kB jdk.graal.compiler 154.26kB byte[] for embedded resources
1.39kB for 2 more packages 1.38MB for 884 more object types
--------------------------------------------------------------------------------
Recommendations:
HEAP: Set max heap for improved and more predictable memory usage.
CPU: Enable more CPU features with '-march=native' for improved performance.
--------------------------------------------------------------------------------
0.8s (4.6% of total time) in 35 GCs | Peak RSS: 1.93GB | CPU load: 9.61
--------------------------------------------------------------------------------
Build artifacts:
/home/janedoe/helloworld/helloworld (executable)
/home/janedoe/helloworld/helloworld.debug (debug_info)
/home/janedoe/helloworld/sources (debug_info)
================================================================================
Finished generating 'helloworld' in 17.0s.
构建阶段 #
初始化 #
在此阶段,原生镜像构建过程将被设置,并且将初始化 Features
。
原生镜像类型
默认情况下,原生镜像会生成可执行文件,但它也可以生成 原生共享库 和 静态可执行文件。
Java 版本信息
原生镜像进程的 Java 和供应商版本。两者也用于生成的原生二进制文件中的 java.vm.version
和 java.vendor.version
属性。在 提交问题 时,请报告版本和供应商。
Graal 编译器
Graal 编译器使用的选定优化级别和目标机器类型。优化级别可以使用 -O
选项控制,默认值为 2
,这将启用积极的优化。使用 -Ob
启用快速构建模式,这将加快 编译阶段。这在开发期间非常有用,可以缩短镜像构建时间。使用 -Os
优化尺寸。目标机器类型可以使用 -march
选项选择,在 AMD64 上默认为 x86-64-v3
,在 AArch64 上默认为 armv8-a
。有关如何使用此选项的建议,请参见 此处。
在 Oracle GraalVM 上,该行还显示有关 Profile-Guided Optimizations (PGO) 的信息。
off
: 未使用 PGOinstrument
: 生成的可执行文件或共享库已进行检测以收集 PGO 数据(--pgo-instrument
)user-provided
: 启用了 PGO,并使用用户提供的配置文件(例如--pgo default.iprof
)ML-inferred
: 使用机器学习 (ML) 模型来静态推断控制分支拆分的配置文件。
C 编译器
原生镜像构建过程使用的 C 编译器可执行文件、供应商、目标体系结构和版本信息。
垃圾收集器
生成的执行文件中使用的垃圾收集器
- 串行 GC 是默认的 GC,针对低内存占用和小型 Java 堆尺寸进行了优化。
- G1 GC(在 GraalVM 社区版中不可用)是一个多线程 GC,它针对减少停止世界暂停进行了优化,从而提高了延迟,同时实现了高吞吐量。
- Epsilon GC 不执行任何垃圾收集,专为只分配少量内存的非常短运行的应用程序而设计。
有关更多信息,请参见 有关内存管理的文档。
最大堆尺寸
默认情况下,堆尺寸限制为系统内存的一定百分比,允许垃圾收集器根据其策略自由分配内存。在调用原生可执行文件时使用 -Xmx
选项(例如 ./myapp -Xmx64m
用于 64MB)来限制最大堆尺寸,以实现更低且更可预测的内存占用。这在某些情况下还可以提高延迟。在使用原生镜像构建时使用 -R:MaxHeapSize
选项来预先配置最大堆尺寸。
用户特定功能
所有由用户提供或专门启用的 Features
,或隐式为用户注册,例如由框架注册。GraalVM 原生镜像部署了许多内部功能,这些功能未包含在此列表中。
实验选项
所有活动实验选项的列表,包括它们的来源以及可能的 API 选项替代方法(如果有)。
应避免在生产中使用实验选项,并且它们可能会在任何版本中发生变化。如果您依赖于实验功能,并希望将其视为稳定功能,请提交问题。
获取的 NATIVE_IMAGE_OPTIONS
通过 NATIVE_IMAGE_OPTIONS
环境变量获取的额外构建选项。类似于 JAVA_TOOL_OPTIONS
,环境变量的值将作为前缀添加到提供给 native-image
的选项。不允许通过 NATIVE_IMAGE_OPTIONS
传递参数文件。NATIVE_IMAGE_OPTIONS
环境变量旨在供用户、构建环境或工具使用以注入额外的构建选项。
构建资源
构建过程使用的内存限制和线程数。
更准确地说,是 Java 堆的内存限制,因此实际的内存消耗可能更高。请检查构建结束时报告的 峰值 RSS,以了解实际使用了多少内存。默认情况下,构建过程尝试仅使用空闲内存(以避免对构建机器造成内存压力),并且永远不会使用超过 32GB 的内存。如果空闲内存少于 8GB,构建过程将回退到使用总内存的 85%。因此,如果您的机器在构建期间速度很慢,请考虑释放内存,例如关闭不需要的应用程序。可以覆盖默认行为,例如使用 -J-XX:MaxRAMPercentage=60.0
或 -J-Xmx16g
。
默认情况下,构建过程使用所有可用的处理器以最大程度地提高速度,但不会使用超过 32 个线程。使用 --parallelism
选项显式设置线程数(例如,--parallelism=4
)。使用更少的线程可以减少对系统的负载以及内存消耗(以构建过程速度较慢为代价)。
执行分析 #
在此阶段,将执行 指向分析。进度指示器显示分析迭代次数。大量的迭代次数可能表明分析中存在问题,这些问题可能是由于配置错误或功能行为不当造成的。
可达类型、字段和方法
可达类型(基本类型、类、接口和数组)、字段和方法的数量与作为构建过程的一部分加载的类型、字段和方法的总数相比。未达元素数量明显较多可能表明配置问题。为了减少开销,请确保您的类路径和模块路径仅包含构建应用程序所需的条目。
反射注册
为反射注册的类型、字段和方法的数量。数量过多会导致大量的反射开销,减慢构建过程并增加原生二进制文件的大小(请参见 反射元数据)。
JNI 访问注册
为 JNI 访问注册的类型、字段和方法的数量。
外部函数存根
为 外部 函数访问注册的向下调用和向上调用数量。
运行时编译方法
标记为运行时编译的方法数量。此数字仅在将运行时编译构建到可执行文件时显示,例如,在构建 Truffle 语言时。运行时编译方法会考虑堆中的 图编码。
构建宇宙 #
在此阶段,将构建包含所有类型、字段和方法的宇宙,然后使用它来创建原生二进制文件。
解析方法 #
在此阶段,Graal 编译器将解析所有可达方法。进度指示器将定期以越来越长的间隔打印。
内联方法 #
在此阶段,将执行简单的内联方法。进度指示器显示内联迭代次数。
编译方法 #
在此阶段,Graal 编译器将所有可达方法编译为机器代码。进度指示器将定期以越来越长的间隔打印。
布局方法 #
在此阶段,将布局编译后的方法。进度指示器将定期以越来越长的间隔打印。
创建镜像 #
在此阶段,将创建原生二进制文件并写入磁盘。调试信息也作为此阶段的一部分生成(如果请求)。
代码区域
代码区域包含 Graal 编译器为所有可达方法生成的机器代码。因此,减少 可达方法 的数量也会减少代码区域的大小。
代码区域的来源
为了帮助用户理解代码区域中的机器代码的来源,构建输出显示了前几个来源的细分。一个来源是一组 Java 源代码,可以是 JAR 文件、包名或类名,具体取决于可用的信息。例如,java.base
模块 包含 JDK 的基本类。svm.jar
文件、org.graalvm.nativeimage.base
模块以及类似的来源包含 Native Image 运行时的内部源代码。为了减小代码区域的大小,从而减小原生可执行文件的总大小,请根据代码区域细分重新评估应用程序的依赖项。某些库和框架比其他库和框架更适合 Native Image,并且库或框架的较新版本可能会改善(或恶化)它们的代码占用空间。
镜像堆
堆包含可达对象,例如静态应用程序数据、元数据和用于不同目的的 byte[]
(见下文)。
存储在 byte[]
中的通用堆数据
所有 byte[]
对象的总大小,这些对象既不用于 java.lang.String
,也不用于 代码元数据、反射元数据 或 图编码。因此,这也可能包含来自应用程序代码的 byte[]
对象。
存储在 byte[]
中的嵌入式资源
用于存储资源的所有 byte[]
对象的总大小(例如,通过 Class.getResource()
访问的文件)在原生二进制文件中。资源数量显示在 堆 部分。所有资源的列表,包括其模块、名称、来源和大小等附加信息,都包含在 构建报告 中。此信息也可以使用 -H:+GenerateEmbeddedResourcesFile
选项以 JSON 格式请求。此类 JSON 文件根据在 embedded-resources-schema-v1.0.0.json
中定义的 JSON 模式进行验证。
存储在 byte[]
中的代码元数据
用于 代码区域 的元数据的所有 byte[]
对象的总大小。因此,减少 可达方法 的数量也会减小此元数据的尺寸。
存储在 byte[]
中的反射元数据
用于反射元数据的所有 byte[]
对象的总大小,包括类型、字段、方法和构造函数数据。要减少反射元数据的数量,请减少 为反射注册的元素 的数量。
存储在 byte[]
中的图编码
用于图编码的所有 byte[]
对象的总大小。这些编码是 运行时编译方法 的结果。因此,减少此类方法的数量也会减少相应的图编码的尺寸。
堆对齐
为 所选垃圾收集器 对齐堆而保留的额外空间。堆对齐也可能包含特定于 GC 的数据结构。因此,它的尺寸只能通过切换到不同的垃圾收集器来影响。
调试信息
生成的调试信息的总大小(如果已启用)。
其他数据
二进制文件中既不在 代码区域、也不在 堆 也不在 调试信息 中的数据量。此数据通常包含 Native Image 的内部信息,不应占主导地位。
安全报告 #
此部分在 GraalVM 社区版中不可用。
反序列化
这显示了 Java 反序列化是否包含在原生可执行文件中。如果没有包含,则可执行文件的攻击面将减少,因为可执行文件无法通过基于 Java 反序列化的攻击进行利用。
软件物料清单 (SBOM)
此部分指示是否组装了 SBOM 以及以何种方式存储。存储格式包括:embed
,它将 SBOM 嵌入二进制文件中;classpath
,它将 SBOM 保存到类路径;以及 export
,它将 SBOM 作为 JSON 构建工件包含在内。使用 --enable-sbom
激活此功能,该功能默认为 embed
选项。嵌入后,将显示 SBOM 大小。组件数量始终显示。
有关更多信息,请参见 软件物料清单。
反向边控制流完整性 (CFI)
可以使用实验性的 -H:CFI=HW
选项来强制执行控制流完整性 (CFI)。此功能目前仅适用于 Graal 为 Linux AArch64 编译的代码,并利用指针身份验证代码 (PAC) 来确保函数返回地址的完整性。
软件控制流完整性 (CFI)
可以使用实验性的 -H:CFI=SW_NONATIVE
选项在软件中强制执行控制流完整性 (CFI)。此功能目前仅适用于 Graal 为 Linux AMD64 编译的代码,并验证间接分支和方法返回的目标。
建议 #
构建输出可能包含以下一项或多项建议,它们可以帮助您充分利用 Native Image。
AWT
:缺少抽象窗口工具包的可达性元数据
Native Image 分析已包含来自 java.awt
包 的类,但找不到任何可达性元数据。使用 跟踪代理 为您的应用程序收集此类元数据。否则,您的应用程序可能无法正常工作。如果您的应用程序不是桌面应用程序(例如直接使用 Swing 或 AWT),您可能需要重新评估是否确实需要对 AWT 的依赖关系。
CPU
:启用更多 CPU 功能以提高性能
Native Image 构建过程已确定您的 CPU 支持比当前启用的功能更多的功能,例如 AES 或 LSE。如果您在具有相同 CPU 功能支持的相同机器或类似机器上部署您的应用程序,请考虑在构建时使用 -march=native
。此选项允许 Graal 编译器使用所有可用的 CPU 功能,这反过来可以显著提高应用程序的性能。使用 -march=list
列出可以明确指定的所有可用机器类型。
G1GC
:使用 G1 垃圾收集器以提高延迟和吞吐量
G1 垃圾收集器可用于您的平台。考虑在构建时使用 --gc=G1
启用它,以提高应用程序的延迟和吞吐量。有关更多信息,请参见 内存管理文档。为了获得最佳峰值性能,还请考虑使用 配置文件引导优化。
HEAP
:指定最大堆大小
请参考 最大堆大小。
PGO
:使用配置文件引导优化以提高吞吐量
考虑使用配置文件引导优化来优化应用程序以提高吞吐量。这些优化允许 Graal 编译器在 AOT 编译应用程序时利用配置文件信息,类似于它作为 JIT 编译器运行时的信息。为此,请执行以下步骤
- 使用
--pgo-instrument
构建您的应用程序。 - 使用代表性的工作负载运行您的工具化应用程序,以生成以
.iprof
文件形式的配置文件信息。 - 重新构建您的应用程序,并使用
--pgo=<your>.iprof
传入配置文件信息以生成应用程序的优化版本。
相关指南:使用配置文件引导优化优化原生可执行文件。
为了获得最佳峰值性能,还请考虑使用 G1 垃圾收集器。
QBM
:使用快速构建模式以加快构建速度
考虑在开发过程中使用快速构建模式 (-Ob
) 来加快构建速度。更准确地说,此模式减少了 Graal 编译器执行的优化次数,从而减少了 编译阶段 的总时间。快速构建模式不仅对开发很有用,还会导致生成的执行文件的大小更小。但是请注意,由于优化次数减少,可执行文件的总体峰值吞吐量可能会更低。
INIT
:使用严格的镜像堆配置
开始使用 --strict-image-heap
来减少配置量并为将来的 GraalVM 版本做好准备,在这些版本中,这将是默认值。此模式仅要求存储在镜像堆中的类使用 --initialize-at-build-time
进行标记。这有效地减少了实现构建时初始化所需的配置条目数量。采用新模式时,最好从头开始引入构建时初始化。在此过程中,最好选择单个类(而不是整个包)进行构建时初始化。此外,在迁移到新标志之前,请确保将所有框架依赖关系更新到最新版本,因为它们也可能需要迁移。
请注意,从 GraalVM for JDK 22 开始,Native Image 默认启用
--strict-image-heap
。
资源使用统计信息 #
垃圾回收
所有垃圾收集器中花费的总时间、总 GC 时间除以总进程时间的百分比以及垃圾回收的总次数。大量的回收次数或在收集器中花费的时间通常表示系统处于内存压力下。增加可用内存量以减少构建原生二进制文件的时间。
峰值 RSS
操作系统报告的峰值 驻留集大小。此值表示构建过程消耗的最大内存量。您可能想要将此值与 构建资源部分 中报告的内存限制进行比较。如果有足够的余量并且 GC 统计信息 没有显示任何问题,则可以将系统的总内存量减少到更接近峰值 RSS 的值,以降低运营成本。
CPU 负载
进程使用的 CPU 时间除以总进程时间。增加 CPU 内核数量以减少构建原生二进制文件的时间。
构建工件 #
所有构建工件的列表。 这包括生成的原生二进制文件,但也可能包含其他工件,例如额外的库、C 头文件或调试信息。 其中一些工件必须与原生二进制文件位于同一位置,因为它们在运行时需要。 例如,对于使用 AWT 的应用程序,构建过程还会输出来自 JDK 的库和垫片以提供兼容的 AWT 支持。 这些库需要与原生二进制文件一起复制和分发。 使用 `-H:+GenerateBuildArtifactsFile` 选项指示构建器以 JSON 格式生成构建工件列表的机器可读版本。 这样的 JSON 文件将根据在 build-artifacts-schema-v0.9.0.json
中定义的 JSON 模式进行验证。 此模式还包含对每种可能的工件类型的描述,并说明它们是否在运行时需要。
机器可读的构建输出 #
`native-image` 构建器生成的构建输出是为人类设计的,可能会随着新版本的发布而演变,因此工具不应该以任何方式解析它。 相反,请使用 `-H:BuildOutputJSONFile=<file.json>` 选项指示构建器以 JSON 格式生成机器可读的构建输出,例如,可用于构建监控工具。 这样的 JSON 文件将根据在 build-output-schema-v0.9.3.json
中定义的 JSON 模式进行验证。 请注意,仅当构建成功时才会生成 JSON 文件。
以下示例说明了如何在 CI/CD 构建管道中使用它来检查可达方法的数量是否超过某个阈值。
native-image -H:BuildOutputJSONFile=build.json HelloWorld
# ...
cat build.json | python3 -c "import json,sys;c = json.load(sys.stdin)['analysis_results']['methods']['reachable']; assert c < 12000, f'Too many reachable methods: {c}'"
Traceback (most recent call last):
File "<string>", line 1, in <module>
AssertionError: Too many reachable methods: 12128
彩色构建输出 #
默认情况下,`native-image` 构建器在找到合适的终端时会对构建输出进行颜色编码,以提高可读性。 它还尊重 NO_COLOR
、CI
和 TERM
环境变量,以检查颜色支持。 要明确控制彩色输出,请将 `--color` 选项设置为 `always`、`never` 或 `auto`(默认值)。