JVM 中的高级选项

1、概览

Java 虚拟机(JVM)是驱动 Java 应用程序的强大引擎。它具有高度可定制性,通过标准选项提供基本配置,通过非标准选项进行一般性性能调优,以及通过高级选项实现精确控制。

高级选项允许开发人员对性能进行微调,诊断问题,并尝试最前沿的功能。

本文将带你了解最著名的高级 JVM 选项以及如何使用它们,从而对 JVM 行为进行更精细的控制。

2、JVM 选项的分类

JVM 参数可分为三大类:

  • 标准选项-version-help
  • 非标准选项-X: options)
  • 高级选项-XX: options)

3、理解高级 JVM 选项

高级选项不仅限于基本配置,还可以设置 JVM 的更低级属性。这些选项允许我们调整性能关键参数,如垃圾回收、内存管理和运行时诊断。

其中一些高级选项也是常用的最重要的 JVM 参数。不过,由于它们可以针对特定应用场景进行微调,我们必须谨慎使用。在不清楚应用程序行为的情况下过度定制,可能会导致性能低下、崩溃或意外行为。

此外,高级 JVM 选项并不能保证为所有 JVM 实现所支持,而且可能会发生变化。因此,由于这些选项会随着 JVM 的更新而变化,有些选项可能会过时,或者在较新版本中表现不同。

例如,Java 并发标记和清理垃圾收集(CMS)算法就曾出现过这种情况,该算法在 Java 9 中被弃用,并在 Java 14 中被删除。通过关注官方文档,我们可以在发生任何变化之前及时了解情况。

4、垃圾收集调整

垃圾回收对内存管理至关重要,但也会带来影响性能的停顿。高级选项可控制垃圾回收行为,确保应用程序运行更流畅。

从 Java 9 开始,默认情况下使用垃圾优先的垃圾收集器(G1),旨在平衡吞吐量和延迟。

为了克服 G1 的延迟限制,JDK12 引入了 Shenandoah GC,可以使用 -XX:+UseShenandoahGC 选项启用它。Shenandoah 的可用性取决于 JDK 供应商和版本。

还可以根据专门的工作负载使用其他实现方式。Epsilon 垃圾收集器也非常适合用于性能调优,以检查垃圾收集是否会影响我们程序的性能。

5、内存管理

如上所述,垃圾回收是内存管理的重要组成部分,但它只是 JVM 中更大的内存管理生态系统的一部分。

要实现最佳性能,同样重要的是配置内存分配、管理堆大小以及了解堆外内存的工作原理,特别是对于内存密集型应用或有特定性能要求的系统。

回顾一下与内存管理相关的一些高级 JVM 选项:

  • -XX:InitialHeapSize-XX:MaxHeapSize:定义初始和最大堆大小(单位是字节)。
  • -XX:MetaspaceSize-XX:MaxMetaspaceSize:定义元空间区域的初始大小和最大大小。
  • -XX:InitialRAMPercentage-XX:MaxRAMPercentage :将初始堆大小和最大堆大小定义为系统可用内存的百分比。这些设置允许 JVM 动态调整其内存使用量,提供更好的适应性。
  • -XX:MinHeapFreeRatio-XX:MaxHeapFreeRatio:定义了在 GC 循环后,堆中可用空间的最小和最大百分比。
  • -XX:+AlwaysPreTouch:通过在 JVM 初始化过程中预热 Java 堆来减少延迟。因此,每个堆页面都会在 JVM 启动时初始化,而不是在应用程序运行期间逐步初始化。
  • -XX:MaxDirectMemorySize:定义可为直接字节缓冲区保留的内存大小
  • -XX:CompressedClassSpaceSize:定义使用压缩类指针(-XX:-UseCompressedClassPointers)时,为在元空间中存储类元数据分配的最大内存。

6、即时编译(JT)

即时编译(JIT)是一个重要的 JVM 组件,可在运行时将字节码编译为本地机器码,从而提高 Java 应用程序的性能。JIT 编译器在默认情况下是启用的,除非是为了调查 JIT 编译问题,否则最好不要禁用它。

回顾一下用于配置和调整 JIT 编译的高级 JVM 选项:

  • -XX:CICompilerCount:定义用于 JIT 编译的编译器线程数。默认值与可用 CPU 和内存的数量成正比。
  • -XX:ReservedCodeCacheSize:定义分配用于存储 JIT 编译的本地代码的内存区域的最大大小。
  • -XX:CompileThreshold:定义方法首次编译前的方法调用次数(阈值)。
  • -XX:MaxInlineSize:定义 JIT 编译器可以内联的方法的最大允许大小(以字节为单位)。

7、诊断和调试

诊断和调试对于识别和解决 Java 应用程序中的问题(如性能瓶颈、内存泄漏和意外行为)至关重要。

回顾一下与诊断和调试相关的高级 JVM 选项:

  • -XX:+HeapDumpOnOutOfMemoryError:当发生 OutOfMemoryError 时生成 Heap Dump。
  • -XX:HeapDumpPath:定义保存 Heap Dump 的文件路径。
  • -XX:+PrintCompilation:记录 JIT 编译过程。
  • -XX:+LogCompilation:将详细的 JIT 编译日志写入文件。
  • -XX:+UnlockDiagnosticVMOptions:解锁默认情况下不可用的诊断 JVM 选项。
  • -XX:+ExitOnOutOfMemoryError:强制 JVM 在遇到 OutOfMemoryError 时立即退出。
  • -XX:+CrashOnOutOfMemoryError - 强制 JVM 生成核心 Dump,并在发生 OutOfMemoryError 时崩溃。
  • -XX:ErrorFile:定义发生无法恢复的错误时保存错误数据的文件路径。
  • -XX:NativeMemoryTracking:定义跟踪 JVM Native 内存使用情况的模式(off/summary/detail)。
  • -XX:+PrintNMTStatistics:启用在 JVM 退出时打印收集的 Native 内存跟踪数据。只有启用 Native 内存跟踪(-XX:NativeMemoryTracking)后才能使用。

Java 9 起,用于记录 GC 信息的高级 JVM 选项 -XX:+PrintGC-XX:+PrintGCDetails 已被弃用,应由统一日志选项 -Xlog 代替。

8、自适应

上面已经介绍了许多强大的高级 JVM 选项,这些选项可能会让我们在配置和调优 JVM 以满足特定需求时感到不知所措。JVM 通过其自适应机制(Ergonomics)提供了解决方案,它会根据底层硬件和运行时条件自动调整自身行为,从而提升应用程序性能。

列出当前环境中所有的自适应默认值:

java -XX:+PrintFlagsFinal -version

虽然自适应机制旨在设置合理的默认值,但这些默认值不一定总能满足我们的应用需求。

9、总结

本文介绍了常用的一些高级 JVM 参数,以及如何使用它们来提高垃圾回收、内存管理和运行时的性能。


Ref:https://www.baeldung.com/jvm-advanced-options