1. 概述

HotSpot JVM 提供了大量可调优的参数(tuning flags),用于精细化控制运行时行为。由于这类参数多达数百个,记住它们及其默认值几乎不可能,容易踩坑。

本文将介绍几种高效发现和使用这些调优参数的方法,帮助你在性能调优时有的放矢。

2. Java 启动参数分类

java 命令支持多种类型的启动参数,主要分为以下两类:

  • 标准选项(Standard Options)
    所有 JVM 实现都必须支持,稳定可靠。例如 -classpath(或 -cp)、-version 等,日常开发中频繁使用。

  • ⚠️ 非标准选项(Extra Options)
    -X 开头,不保证跨 JVM 兼容,可能随时变更。例如 -Xmx512m 设置堆大小。

    更进一步地,-XX 开头的参数属于高级调优选项,功能强大但风险较高,需谨慎使用。

本文重点关注 -XX 类型的高级 JVM 调优参数。

3. JVM 调优参数的查看方式

3.1 查看所有全局调优参数

要列出当前 JVM 支持的所有调优参数及其当前值,可以使用:

java -XX:+PrintFlagsFinal -version

输出示例如下:

[Global flags]
    uintx CodeCacheExpansionSize                   = 65536                                  {pd product} {default}
     bool CompactStrings                           = true                                   {pd product} {default}
     bool DoEscapeAnalysis                         = true                                   {C2 product} {default}
   double G1ConcMarkStepDurationMillis             = 10.000000                                 {product} {default}
   size_t G1HeapRegionSize                         = 1048576                                   {product} {ergonomic}
    uintx MaxHeapFreeRatio                         = 70                                     {manageable} {default}

// 其他参数...
openjdk version "14" 2020-03-17
OpenJDK Runtime Environment (build 14+36-1461)
OpenJDK 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)

✅ 输出中 {default} 表示该参数为默认值,{ergonomic} 表示由 JVM 自适应策略决定。

3.2 查看实验性参数

某些参数是实验性的,需显式解锁才能查看:

java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions \
     -XX:+PrintFlagsFinal -version | wc -l

输出结果为 809,说明启用了诊断和实验性选项后,可见参数数量显著增加。

❗ 实验性参数(Experimental)可能在后续版本中移除或变更,生产环境禁用。

3.3 查看 JVMCI 相关参数

从 Java 9 开始,JVM 编译器接口(JVMCI)允许使用 Java 编写的编译器(如 GraalVM)作为动态编译器。

要查看与 JVMCI 相关的参数,需启用对应选项:

java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions \
     -XX:+JVMCIPrintProperties -XX:+EnableJVMCI -XX:+PrintFlagsFinal -version | wc -l

输出为 1516,说明 JVMCI 引入了大量新参数。

✅ 日常调优中,通常只需关注全局、诊断和实验性参数即可满足大部分需求。

3.4 组合技巧:快速定位目标参数

我们可以将常用参数组合成别名,方便快速搜索:

alias jflags="java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version"

例如,查找与软引用(Soft Reference)相关的参数:

jflags | grep Soft

输出:

size_t SoftMaxHeapSize                          = 4294967296                             {manageable} {ergonomic}
intx SoftRefLRUPolicyMSPerMB                    = 1000                                   {product} {default}

✅ 从结果可推断,SoftRefLRUPolicyMSPerMB 控制软引用回收策略,单位为毫秒/每MB堆空间。

4. 调优参数的类型

回顾 PrintFlagsFinal 的输出,每个参数都有明确的类型:

[Global flags]
    uintx CodeCacheExpansionSize                   = 65536                                  {pd product} {default}
     bool CompactStrings                           = true                                   {pd product} {default}
     bool DoEscapeAnalysis                         = true                                   {C2 product} {default}
   double G1ConcMarkStepDurationMillis             = 10.000000                                 {product} {default}
   size_t G1HeapRegionSize                         = 1048576                                   {product} {ergonomic}
    uintx MaxHeapFreeRatio                         = 70                                     {manageable} {default}

参数类型说明

类型 说明
bool 布尔型,启用/禁用某项功能
intx 整数型(32位或64位)
uintx 无符号整数型
double 浮点型
size_t 大小型(如内存容量)

布尔型参数的使用

  • ✅ 启用:-XX:+FlagName
    例如:-XX:+PrintGC 开启GC日志

  • ❌ 禁用:-XX:-FlagName
    例如:-XX:-RestrictContended 禁用字段填充优化

非布尔型参数的赋值方式

支持多种分隔符,具体取决于 JVM 实现:

-XX:ObjectAlignmentInBytes=16
-Xms5g
-Xlog:gc
-XX:MaxHeapSize:2g

⚠️ 建议统一使用 = 分隔,避免歧义。

5. 文档与源码:深入理解参数含义

知道参数名只是第一步,理解其背后的行为才是关键。

官方文档

首选查阅 JDK 工具规范文档,其中对标准和部分 -XX 参数有详细说明。

源码分析

当文档不足时,直接看 HotSpot 源码是最直接的方式。

PrintFlagsFinal 为例:

git clone git@github.com:openjdk/jdk14u.git openjdk
cd openjdk/src/hotspot
grep -FR 'PrintFlagsFinal' .

输出:

./share/runtime/globals.hpp:  product(bool, PrintFlagsFinal, false,                                   
./share/runtime/init.cpp:  if (PrintFlagsFinal || PrintFlagsRanges) {

✅ 在 globals.hpp 中可找到参数定义,包括类型、默认值和属性。

✅ 在 init.cpp 中可看到其使用逻辑,便于理解执行时机和影响范围。

💡 推荐使用 GitHub 上的 openjdk/jdk 仓库,分支清晰,搜索方便。

6. 总结

本文系统介绍了如何:

  • ✅ 使用 -XX:+PrintFlagsFinal 查看所有调优参数
  • ✅ 解锁实验性和诊断参数以扩大搜索范围
  • ✅ 通过别名 + grep 快速定位目标参数
  • ✅ 理解不同参数类型的使用方式
  • ✅ 结合官方文档与源码深入理解参数行为

这些技巧简单粗暴但极其实用,能显著提升 JVM 调优效率。记住:调优不是猜谜,而是基于证据的系统性优化


原始标题:Exploring JVM Tuning Flags