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 调优效率。记住:调优不是猜谜,而是基于证据的系统性优化。