- 适用于 JDK 24 的 GraalVM(最新)
- 适用于 JDK 25 的 GraalVM(早期访问)
- 适用于 JDK 21 的 GraalVM
- 适用于 JDK 17 的 GraalVM
- 存档
- 开发构建
Native Image 构建输出
在这里您可以找到关于 GraalVM Native Image 构建输出的信息。下面是构建 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.
构建阶段 #
初始化 #
在此阶段,Native Image 构建过程被设置,并且 Features
被初始化。
Native Image 类型
默认情况下,Native Image 生成可执行文件,但它也可以生成原生共享库和静态可执行文件。
Java 版本信息
Native Image 进程的 Java 和供应商版本。两者也用于生成的原生二进制文件中的 java.vm.version
和 java.vendor.version
属性。当您提交问题时,请报告版本和供应商信息。
Graal 编译器
Graal 编译器使用的选定优化级别和目标机器类型。优化级别可以通过 -O
选项控制,默认为 2
,这会启用激进优化。使用 -Ob
启用快速构建模式,这会加快编译阶段。这在开发过程中用于减少镜像构建时间非常有用。使用 -Os
优化大小。目标机器类型可以使用 -march
选项选择,在 AMD64 上默认为 x86-64-v3
,在 AArch64 上默认为 armv8-a
。有关如何使用此选项的建议,请参见此处。
在 Oracle GraalVM 上,该行还会显示关于配置文件引导优化 (PGO) 的信息。
off
: 未使用 PGOinstrument
: 生成的可执行文件或共享库被插桩以收集 PGO 数据 (--pgo-instrument
)user-provided
: PGO 已启用并使用用户提供的配置文件(例如--pgo default.iprof
)ML-inferred
: 使用机器学习 (ML) 模型来静态推断控制分割分支的配置文件。
C 编译器
Native Image 构建过程使用的 C 编译器可执行文件、供应商、目标架构和版本信息。
垃圾收集器
生成的本机可执行文件中使用的垃圾收集器
- Serial GC 是默认的 GC,为低内存占用和小型 Java 堆大小进行了优化。
- G1 GC(GraalVM Community Edition 中不提供)是多线程 GC,旨在减少“stop-the-world”暂停,从而在实现高吞吐量的同时提高延迟。
- Epsilon GC 不执行任何垃圾收集,专为运行时间极短且仅分配少量内存的应用程序而设计。
更多信息请参见内存管理文档。
最大堆大小
默认情况下,堆大小限制为系统内存的特定百分比,允许垃圾收集器根据其策略自由分配内存。在调用原生可执行文件时使用 -Xmx
选项(例如 ./myapp -Xmx64m
代表 64MB)来限制最大堆大小,以实现更低且更可预测的内存占用。这在某些情况下还可以改善延迟。在使用 Native Image 构建时使用 -R:MaxHeapSize
选项来预配置最大堆大小。
用户特定功能
所有由用户提供或特别启用,或由框架隐式注册的Features
。GraalVM Native Image 部署了许多内部功能,这些功能不在此列表中。
实验性选项
所有活动实验性选项的列表,包括它们的来源以及可能存在的 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 访问的类型、字段和方法的数量。
外部函数存根
为外部函数访问注册的 downcall 和 upcall 数量。
运行时编译方法
标记为运行时编译的方法数量。此数字仅在可执行文件中内置运行时编译时显示,例如在构建 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[]
中的嵌入资源
所有用于在原生二进制文件中存储资源(例如,通过 Class.getResource()
访问的文件)的 byte[]
对象的总大小。资源的数量显示在堆部分。包含所有资源(包括其模块、名称、来源和大小等附加信息)的列表包含在构建报告中。此信息也可以使用 -H:+GenerateEmbeddedResourcesFile
选项以 JSON 格式请求。这样的 JSON 文件根据embedded-resources-schema-v1.0.0.json
中定义的 JSON 模式进行验证。
存储在 byte[]
中的代码元数据
用于代码区域元数据的所有 byte[]
对象的总大小。因此,减少可达方法的数量也会减少此元数据的大小。
存储在 byte[]
中的反射元数据
所有用于反射元数据(包括类型、字段、方法和构造函数数据)的 byte[]
对象的总大小。要减少反射元数据的数量,请减少注册用于反射的元素的数量。
存储在 byte[]
中的图编码
所有用于图编码的 byte[]
对象的总大小。这些编码是运行时编译方法的结果。因此,减少此类方法的数量也会减少相应图编码的大小。
堆对齐
为选定的垃圾收集器对齐堆而保留的额外空间。堆对齐也可能包含特定于 GC 的数据结构。因此,其大小只能通过切换到不同的垃圾收集器来影响。
调试信息
生成的调试信息的总大小(如果启用)。
其他数据
二进制文件中既不在代码区域、也不在堆、也不在调试信息中的数据量。这些数据通常包含 Native Image 的内部信息,不应占据主导地位。
安全报告 #
此部分在 GraalVM Community Edition 中不可用。
反序列化
这显示了 Java 反序列化是否包含在原生可执行文件中。如果未包含,则可执行文件的攻击面会减小,因为可执行文件不能被基于 Java 反序列化的攻击利用。
软件物料清单 (SBOM)
本节指示是否组装了 SBOM 以及它以何种方式存储。存储格式包括:embed
,将 SBOM 嵌入到二进制文件中;classpath
,将 SBOM 保存到类路径中;以及 export
,将 SBOM 作为 JSON 构建产物包含。使用 --enable-sbom
激活此功能,该功能默认为 embed
选项。嵌入时,会显示 SBOM 大小。组件数量始终显示。
有关更多信息,请参阅软件物料清单。
反向边缘控制流完整性 (CFI)
控制流完整性 (CFI) 可以通过实验性的 -H:CFI=HW
选项强制执行。此功能目前仅适用于 Graal 为 Linux AArch64 编译的代码,并利用指针认证码 (PAC) 来确保函数返回地址的完整性。
软件控制流完整性 (CFI)
控制流完整性 (CFI) 可以通过实验性的 -H:CFI=SW_NONATIVE
选项在软件中强制执行。此功能目前仅适用于 Graal 为 Linux AMD64 编译的代码,并验证间接分支和方法返回的目标。
建议 #
构建输出可能包含以下一项或多项建议,这些建议可帮助您充分利用 Native Image。
AWT
: 抽象窗口工具包缺少可达性元数据
Native Image 分析已包含来自java.awt
包的类,但找不到任何可达性元数据。使用跟踪代理为您的应用程序收集此类元数据。否则,您的应用程序可能无法正常工作。如果您的应用程序不是桌面应用程序(例如直接使用 Swing 或 AWT),您可能需要重新评估是否确实需要 AWT 依赖项。
HOME
: 运行二进制文件时设置 java.home
Native Image 分析已检测到 System.getProperty("java.home")
的使用。为确保其返回有效值,请通过向二进制文件传递 -Djava.home=<path>
选项来设置 java.home
。如果未设置,System.getProperty("java.home")
将返回 null
。
CPU
: 启用更多 CPU 功能以提高性能
Native Image 构建过程已确定您的 CPU 支持比当前启用的更多功能,例如 AES 或 LSE。如果您在支持相同 CPU 功能的同一台机器或类似机器上部署应用程序,请考虑在构建时使用 -march=native
。此选项允许 Graal 编译器使用所有可用的 CPU 功能,这反过来可以显著提高应用程序的性能。使用 -march=list
列出所有可以显式指定的目标机器类型。
G1GC
: 使用 G1 垃圾收集器以提高延迟和吞吐量
G1 垃圾收集器适用于您的平台。考虑在构建时使用 --gc=G1
启用它,以提高应用程序的延迟和吞吐量。更多信息请参见内存管理文档。为了获得最佳峰值性能,还请考虑使用配置文件引导优化。
HEAP
: 指定最大堆大小
请参阅最大堆大小。
PGO
: 使用配置文件引导优化以提高吞吐量
考虑使用配置文件引导优化 (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
(默认)。