type
Post
status
Published
date
Jul 21, 2024
slug
summary
tags
Graal
GraalVM
Java
category
技术分享
icon
password
构建选项
march=native如果您的二进制文件将在和编译的机器同一类型cpu下工作,可以打开这个功能,使得GraalVM为你启用更多的CPU功能。
Ob在开发时构建选项添加这个,可以加快构建速度,但是这样会禁用掉绝大多数的优化。
GC
原生镜像在执行时并不运行在 Java HotSpot VM 上,而是运行在 GraalVM 提供的运行时系统上。该运行时包括所有必要的组件,其中之一就是内存管理。
本机映像在运行时分配的 Java 对象驻留在称为“Java Heap”的区域中。Java Heap是在本机映像启动时创建的,并且在本机映像运行时可能会增大或减小。当堆已满时,会触发垃圾回收以回收不再使用的对象的内存。
为了管理 Java Heap,Native Image 提供了不同的垃圾收集器 (GC) 实现:
- Serial GC是 GraalVM Native Image 中的默认 GC。它针对低内存占用和较小的 Java 堆大小进行了优化。添加
-gc=serial构建参数,启动这个破GC。
- G1 GC是一种多线程 GC,经过优化可减少 Stop-the-world 暂停,从而改善延迟,同时实现高吞吐量。要启用它,请将选项传递
-gc=G1给native-image构建器。目前,G1 垃圾收集器可与 Linux AMD64 和 AArch64 架构上的 Native Image 一起使用。(GraalVM 社区版中不可用。)
- Epsilon GC(适用于 GraalVM 21.2 或更高版本)是一种无操作垃圾收集器,它不执行任何垃圾收集,因此永远不会释放任何分配的内存。此 GC 的主要用例是运行时间非常短且仅分配少量内存的应用程序。要启用 Epsilon GC,构建参数添加
-gc=epsilon启用该GC。
怎么好用的GC还要付钱,甲骨文要变微软Plus?当我没说,带G1GC的版本你可以直接下载下来直接用。
SerialGC性能调整
为了调整 GC 性能和内存占用,可以使用以下选项:
XX:MaximumHeapSizePercent如果未指定最大 Java 堆大小,则使用物理内存大小的百分比作为最大 Java 堆大小。
XX:MaximumYoungGenerationSizePercent年轻代的最大大小占最大 Java 堆大小的百分比。
XX:±CollectYoungGenerationSeparately(自 GraalVM 21.0 起)- 确定完整 GC 是单独收集年轻代还是与老代一起收集。如果启用,这可能会减少完整 GC 期间的内存占用。但是,完整 GC 可能需要更多时间。
XX:MaxHeapFree(自 GraalVM 21.3 起)- 收集后仍为分配保留的可用内存块的最大总大小(以字节为单位),因此不会返回给操作系统。
H:AlignedHeapChunkSize(只能在图像构建时指定) - 堆块的大小(以字节为单位)。
H:MaxSurvivorSpaces(自 GraalVM 21.1 起,只能在镜像构建时指定)- 用于年轻代的幸存者空间数量,即对象晋升到老一代的最大年龄。值为 0 时,年轻代收集中幸存下来的对象将直接晋升到老一代。
H:LargeArrayThreshold(只能在构建映像时指定)- 数组的大小等于或大于该大小时,将在其自己的堆块中分配该数组。被视为较大的数组分配起来更昂贵,但它们永远不会被 GC 复制,这可以减少 GC 开销。
以下选项
-H:InitialCollectionPolicy=BySpaceAndTime仅适用于:XX:PercentTimeInIncrementalCollection确定 GC 应花多少时间进行年轻代收集。默认值为 50,GC 会尝试平衡年轻代收集和完整收集所花费的时间。增加此值将减少完整 GC 的次数,这可以提高性能,但可能会增加内存占用。减少此值将增加完整 GC 的次数,这可以提高内存占用,但可能会降低性能。
G1GC性能调整
G1 GC 是一种自适应垃圾收集器,其默认设置使其无需修改即可高效工作。但是,它可以根据特定应用程序的性能需求进行调整。以下是进行性能调整时可以指定的一小部分选项:
H:G1HeapRegionSize(只能在图像构建时指定) - G1 区域的大小。
XX:MaxRAMPercentage如果未指定最大堆大小,则使用物理内存大小的百分比作为最大堆大小。
XX:MaxGCPauseMillis最大暂停时间的目标。
XX:ParallelGCThreads垃圾收集暂停期间用于并行工作的最大线程数。
XX:ConcGCThreads用于并发工作的最大线程数。
XX:InitiatingHeapOccupancyPercent触发标记周期的 Java 堆占用率阈值。
XX:G1HeapWastePercent收集候选集允许的未回收空间。如果收集候选集的可用空间低于该值,G1 将停止空间回收阶段。
垃圾回收详细打印
执行编译出来的二进制时,可以使用以下选项打印一些有关垃圾回收的信息。打印哪些数据信息取决于所使用的 GC。
XX:+PrintGC打印每次垃圾收集的基本信息
XX:+VerboseGC可以添加以打印进一步的垃圾收集详细信息
内存管理
Java Heap
和普通的Java一样他也有配置Java堆的选项:
执行编译好的二进制文件时,将根据系统配置和使用的 GC 自动确定合适的 Java 堆设置。 要覆盖此自动机制并在运行时明确设置堆大小,可以使用以下命令行选项:
Xmx最大堆大小(以字节为单位)
Xms最小堆大小(以字节为单位)
Xmn年轻代的大小(以字节为单位)
还可以在镜像构建时预先配置默认堆设置。然后指定的值将在运行时用作默认值:
R:MaxHeapSize(自 GraalVM 20.0 起)- 最大堆大小(以字节为单位)
R:MinHeapSize(自 GraalVM 20.0 起)- 最小堆大小(以字节为单位)
R:MaxNewSize(自 GraalVM 20.0 起)- 年轻代的大小(以字节为单位)
引用压缩
Oracle GraalVM 支持对使用 32 位(而非 64 位)的 Java 对象进行压缩引用。压缩引用默认启用,并且会对内存占用产生很大影响。但是,它们将最大 Java 堆大小限制为 32 GB 内存。如果需要超过 32 GB,则需要禁用压缩引用。
H:±UseCompressedReferences(只能在native-image时指定) - 确定是否使用 32 位 Java 对象引用。
Native Memory
Native Image 能分配独立于 Java 堆外的内存。一个常见用例是
java.nio.DirectByteBuffer直接引用Native Memory。XX:MaxDirectMemorySize直接缓冲区分配的最大大小
引导优化
JIT 编译器相对于AOT 编译器的一个优势是它能够分析应用程序的运行时行为。例如,HotSpot 会跟踪语句的每个分支执行的次数
if。此信息称为“profile”,会传递给二级 JIT 编译器(Graal)。然后,二级 JIT 编译器会假设该if语句将继续以相同的方式运行,并使用配置文件中的信息来优化该语句。AOT 编译器通常不具备分析信息,并且通常仅限于静态代码视图。这意味着,除非采用启发式方法,否则 AOT 编译器会认为每个
if语句的每个分支在运行时发生的可能性相同;每个方法被调用的可能性与其他方法一样;并且每个循环重复的次数相同。这让 AOT 编译器处于劣势 —如果没有分析信息,就很难生成与 JIT 编译器质量相同的机器代码。配置文件引导优化 (PGO) 是一种将配置文件信息带给 AOT 编译器的技术,以提高其输出在性能和大小方面的质量。
注意:PGO 在 GraalVM 社区版中不可用。
构建带有PGO的二进制文件
进行profile收集需要在构建参数中添加
--pgo-instrument 构建一个具有PGO收集的二进制文件(这个过程可能需要很长一段时间),随后我们执行以下代码(GraalVM是我编译出来的二进制文件的名称):随后我们在构建参数中添加
--pgo=/home/fuqiuluo/IdeaProjects/GraalVM/gprofile.iprof 将profile带入构建,使得AOT编译期可以引导优化。例如我们有以上代码,这是他在各种情况下的性能表现
GraalVM JIT运行表现
PGO收集时运行时表现
PGO优化后表现
有所提升,但不高,主要是因为优化版本提供的profile文件允许编译器区分哪些代码对性能很重要(即热代码),哪些代码不重要(即冷代码,例如错误处理)。有了这种区分,编译器可以决定更多地关注优化热代码,而较少关注或根本不关注冷代码。这与 JVM 所做的方法类似 - 在运行时识别代码的热门部分并在运行时编译这些部分。主要区别在于 Native Image PGO 会提前进行分析和优化。
在我的这段代码中没有迎合AOT的优化,但是因为native运行,在这种CPU密集的场合AOT的确比JIT要快,https://www.graalvm.org/latest/reference-manual/native-image/optimizations-and-performance/PGO/basic-usage/官方的这个示例,更突出PGO优化的好处。https://medium.com/graalvm/profile-guided-optimization-for-native-image-f015f853f9a8
合并来自多个来源的配置文件
PGO 基础架构可让您使用Native Image Configure Tool将多个profile文件合并为一个profile文件。合并配置文件意味着生成的profile文件将包含所提供profile文件中的所有类型、方法和profile文件条目的并集。
用法
要将两个profile文件profile_1.iprof和profile_2.iprof合并为一个名为output_profile.iprof的文件,请使用以下命令:
还有一种方法可以使用选项指定目录作为profile文件的来源
--input-dir=<path>。然后它只会在给定目录中搜索profile文件,不包括子目录。