目录
- [第一章:JVM 调优概述](#第一章:JVM 调优概述)
- [第二章:常用 JVM 参数](#第二章:常用 JVM 参数)
- 第三章:内存调优
- [第四章:GC 调优](#第四章:GC 调优)
- 第五章:性能监控命令
- 第六章:问题排查流程
- 第七章:实战案例
- 第八章:命令速查表
- 第九章:监控脚本
- 第十章:生产环境配置
第一章:JVM 调优概述
1.1 JVM 调优的目标
- 提高吞吐量:减少 GC 时间,提高应用处理能力
- 降低延迟:减少 GC 停顿时间,提高响应速度
- 减少内存占用:优化内存使用,避免内存泄漏
- 提高稳定性:避免 OOM,提高系统稳定性
1.2 JVM 调优的原则
- 先监控后调优:基于监控数据进行调优
- 逐步调优:一次只调整一个参数
- 测试验证:调优后要进行充分测试
- 记录对比:记录调优前后的性能数据
1.3 JVM 调优的步骤
- 性能监控:使用工具监控 JVM 性能
- 问题识别:识别性能瓶颈和问题
- 参数调优:调整 JVM 参数
- 效果验证:验证调优效果
- 持续监控:持续监控性能变化
第二章:常用 JVM 参数
2.1 内存相关参数
堆内存参数
bash
# 设置堆内存初始大小
-Xms2g
# 设置堆内存最大大小
-Xmx4g
# 设置新生代大小
-Xmn1g
# 设置新生代中 Eden 和 Survivor 的比例
-XX:SurvivorRatio=8
# 设置老年代和新生代的比例
-XX:NewRatio=2
非堆内存参数
bash
# 设置元空间初始大小
-XX:MetaspaceSize=256m
# 设置元空间最大大小
-XX:MaxMetaspaceSize=512m
# 设置直接内存大小
-XX:MaxDirectMemorySize=1g
2.2 GC 相关参数
GC 选择参数
bash
# 使用 G1 垃圾回收器
-XX:+UseG1GC
# 使用 Parallel GC
-XX:+UseParallelGC
# 使用 CMS GC
-XX:+UseConcMarkSweepGC
# 使用 ZGC
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
GC 调优参数
bash
# 设置 GC 线程数
-XX:ParallelGCThreads=8
# 设置 G1 最大停顿时间
-XX:MaxGCPauseMillis=200
# 设置 G1 区域大小
-XX:G1HeapRegionSize=16m
# 设置 CMS 并发线程数
-XX:ConcGCThreads=4
2.3 监控和日志参数
GC 日志参数
bash
# 启用 GC 日志
-XX:+PrintGC
# 启用详细 GC 日志
-XX:+PrintGCDetails
# 启用 GC 时间戳
-XX:+PrintGCTimeStamps
# 启用 GC 日期戳
-XX:+PrintGCDateStamps
# 设置 GC 日志文件
-Xloggc:/path/to/gc.log
# 启用 GC 日志轮转
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=100M
内存转储参数
bash
# 发生 OOM 时自动生成堆转储
-XX:+HeapDumpOnOutOfMemoryError
# 设置堆转储文件路径
-XX:HeapDumpPath=/path/to/heapdump.hprof
# 发生 OOM 时自动生成堆转储
-XX:+HeapDumpBeforeFullGC
2.4 性能调优参数
JIT 编译参数
bash
# 启用分层编译
-XX:+TieredCompilation
# 设置编译阈值
-XX:CompileThreshold=10000
# 启用方法内联
-XX:+AggressiveOpts
其他性能参数
bash
# 启用压缩指针
-XX:+UseCompressedOops
# 启用压缩类指针
-XX:+UseCompressedClassPointers
# 设置大对象阈值
-XX:PretenureSizeThreshold=1m
第三章:内存调优
3.1 堆内存调优
堆内存大小设置
bash
# 生产环境推荐配置
-Xms4g -Xmx4g -Xmn2g
# 高并发应用配置
-Xms8g -Xmx8g -Xmn4g
# 内存受限环境配置
-Xms1g -Xmx2g -Xmn512m
新生代调优
bash
# Eden 和 Survivor 比例调优
-XX:SurvivorRatio=8 # Eden:Survivor = 8:1:1
# 新生代和老年代比例调优
-XX:NewRatio=2 # 老年代:新生代 = 2:1
3.2 元空间调优
元空间大小设置
bash
# 设置元空间初始大小
-XX:MetaspaceSize=256m
# 设置元空间最大大小
-XX:MaxMetaspaceSize=512m
# 设置元空间增长阈值
-XX:MetaspaceSizeThreshold=128m
3.3 直接内存调优
直接内存设置
bash
# 设置直接内存大小
-XX:MaxDirectMemorySize=1g
# 启用直接内存监控
-XX:+PrintNMTStatistics
第四章:GC 调优
4.1 G1 GC 调优
G1 GC 基本参数
bash
# 启用 G1 GC
-XX:+UseG1GC
# 设置最大停顿时间
-XX:MaxGCPauseMillis=200
# 设置 G1 区域大小
-XX:G1HeapRegionSize=16m
# 设置并发标记线程数
-XX:ConcGCThreads=4
G1 GC 高级参数
bash
# 设置 G1 混合 GC 阈值
-XX:G1MixedGCCountTarget=8
# 设置 G1 混合 GC 停顿时间
-XX:G1MixedGCLiveThresholdPercent=85
# 启用 G1 字符串去重
-XX:+UseStringDeduplication
4.2 Parallel GC 调优
Parallel GC 参数
bash
# 启用 Parallel GC
-XX:+UseParallelGC
# 设置并行 GC 线程数
-XX:ParallelGCThreads=8
# 设置并行 GC 停顿时间
-XX:MaxGCPauseMillis=200
4.3 CMS GC 调优
CMS GC 参数
bash
# 启用 CMS GC
-XX:+UseConcMarkSweepGC
# 设置 CMS 并发线程数
-XX:ConcGCThreads=4
# 设置 CMS 触发阈值
-XX:CMSInitiatingOccupancyFraction=70
# 启用 CMS 并发预清理
-XX:+CMSPrecleaningEnabled
第五章:性能监控命令
5.1 jps 命令
基本用法
bash
# 列出所有 Java 进程
jps
# 列出所有 Java 进程的详细信息
jps -l
# 列出所有 Java 进程的完整信息
jps -v
# 列出所有 Java 进程的完整信息
jps -m
输出示例
bash
$ jps -l
12345 com.example.Application
67890 org.springframework.boot.loader.JarLauncher
5.2 jstat 命令
基本用法
bash
# 监控 GC 情况
jstat -gc <pid> 1s
# 监控 GC 详细情况
jstat -gcutil <pid> 1s
# 监控类加载情况
jstat -class <pid> 1s
# 监控编译情况
jstat -compiler <pid> 1s
输出示例
bash
$ jstat -gc 12345 1s
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1024.0 1024.0 0.0 0.0 8192.0 1024.0 20480.0 1024.0 256.0 128.0 32.0 16.0 5 0.123 1 0.456 0.579
5.3 jmap 命令
基本用法
bash
# 生成堆转储文件
jmap -dump:format=b,file=heapdump.hprof <pid>
# 查看堆内存使用情况
jmap -histo <pid>
# 查看堆内存使用情况(详细)
jmap -histo:live <pid>
# 查看类加载器信息
jmap -clstats <pid>
输出示例
bash
$ jmap -histo 12345
num #instances #bytes class name
----------------------------------------------
1: 12345 1234567 java.lang.String
2: 6789 890123 java.util.HashMap$Node
3: 4567 567890 java.lang.Object[]
5.4 jstack 命令
基本用法
bash
# 生成线程转储文件
jstack <pid> > threaddump.txt
# 生成线程转储文件(包含锁信息)
jstack -l <pid> > threaddump.txt
# 生成线程转储文件(包含本地变量)
jstack -F <pid> > threaddump.txt
输出示例
bash
$ jstack 12345
"main" #1 prio=5 os_prio=0 tid=0x00007f8b8c001000 nid=0x1234 waiting on condition [0x00007f8b8d000000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c0000000> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
5.5 jinfo 命令
基本用法
bash
# 查看 JVM 参数
jinfo <pid>
# 查看特定 JVM 参数
jinfo -flag MaxHeapSize <pid>
# 动态修改 JVM 参数
jinfo -flag +PrintGC <pid>
输出示例
bash
$ jinfo 12345
Attaching to process ID 12345, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0.1+13-LTS
Java System Properties:
java.vm.name = OpenJDK 64-Bit Server VM
java.vm.version = 11.0.1+13-LTS
java.vm.vendor = Oracle Corporation
5.6 jcmd 命令
基本用法
bash
# 列出所有可用的命令
jcmd <pid> help
# 生成堆转储文件
jcmd <pid> GC.run_finalization
# 生成线程转储文件
jcmd <pid> Thread.print
# 生成类直方图
jcmd <pid> GC.class_histogram
# 查看 JVM 参数
jcmd <pid> VM.flags
第六章:问题排查流程
6.1 内存问题排查
内存泄漏排查步骤
-
监控内存使用情况
bash# 使用 jstat 监控内存使用 jstat -gc <pid> 1s
-
生成堆转储文件
bash# 使用 jmap 生成堆转储 jmap -dump:format=b,file=heapdump.hprof <pid>
-
分析堆转储文件
- 使用 Eclipse MAT 分析堆转储文件
- 查找内存泄漏的根源
- 分析对象引用关系
OOM 问题排查步骤
-
查看 OOM 错误信息
bash# 查看应用日志 tail -f application.log
-
分析堆转储文件
bash# 如果配置了自动生成堆转储 ls -la /path/to/heapdump.hprof
-
调整内存参数
bash# 增加堆内存大小 -Xms4g -Xmx4g
6.2 GC 问题排查
GC 频繁问题排查
-
监控 GC 情况
bash# 使用 jstat 监控 GC jstat -gc <pid> 1s
-
分析 GC 日志
bash# 启用 GC 日志 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
-
调整 GC 参数
bash# 调整新生代大小 -Xmn2g # 调整 GC 策略 -XX:+UseG1GC -XX:MaxGCPauseMillis=200
GC 停顿时间过长问题排查
-
监控 GC 停顿时间
bash# 使用 jstat 监控 GC 时间 jstat -gc <pid> 1s
-
分析 GC 日志
bash# 查看 GC 日志中的停顿时间 grep "Total time" gc.log
-
调整 GC 参数
bash# 使用 G1 GC 减少停顿时间 -XX:+UseG1GC -XX:MaxGCPauseMillis=100
6.3 线程问题排查
线程死锁排查
-
生成线程转储文件
bash# 使用 jstack 生成线程转储 jstack <pid> > threaddump.txt
-
分析线程转储文件
- 查找死锁信息
- 分析线程状态
- 查看锁等待情况
线程阻塞排查
-
监控线程状态
bash# 使用 jstack 查看线程状态 jstack <pid> | grep "BLOCKED"
-
分析阻塞原因
- 查看线程堆栈信息
- 分析锁竞争情况
- 查找阻塞的根源
6.4 性能问题排查
CPU 使用率过高排查
-
监控 CPU 使用情况
bash# 使用 top 命令监控 top -p <pid>
-
生成线程转储文件
bash# 使用 jstack 生成线程转储 jstack <pid> > threaddump.txt
-
分析热点方法
bash# 使用 jcmd 生成类直方图 jcmd <pid> GC.class_histogram
响应时间过长排查
-
监控应用性能
bash# 使用 APM 工具监控 # 或者使用 jstat 监控 GC 情况 jstat -gc <pid> 1s
-
分析性能瓶颈
- 分析 GC 情况
- 查看线程状态
- 分析内存使用情况
第七章:实战案例
7.1 内存泄漏排查案例
问题描述
应用运行一段时间后出现 OOM 错误,需要排查内存泄漏问题。
排查步骤
-
监控内存使用情况
bash# 使用 jstat 监控内存使用 jstat -gc 12345 1s
-
生成堆转储文件
bash# 使用 jmap 生成堆转储 jmap -dump:format=b,file=heapdump.hprof 12345
-
分析堆转储文件
- 使用 Eclipse MAT 分析
- 发现大量 String 对象
- 分析对象引用关系
-
定位问题代码
- 查找创建大量 String 的代码
- 分析字符串拼接逻辑
- 优化字符串处理
解决方案
java
// 问题代码
String result = "";
for (int i = 0; i < 10000; i++) {
result += "data" + i;
}
// 优化后代码
StringBuilder result = new StringBuilder();
for (int i = 0; i < 10000; i++) {
result.append("data").append(i);
}
7.2 GC 频繁问题排查案例
问题描述
应用 GC 频繁,影响性能,需要优化 GC 策略。
排查步骤
-
监控 GC 情况
bash# 使用 jstat 监控 GC jstat -gc 12345 1s
-
分析 GC 日志
bash# 查看 GC 日志 tail -f gc.log
-
调整 GC 参数
bash# 调整新生代大小 -Xmn2g # 使用 G1 GC -XX:+UseG1GC -XX:MaxGCPauseMillis=200
解决方案
bash
# 优化后的 JVM 参数
-Xms4g -Xmx4g -Xmn2g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSize=16m
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
7.3 线程死锁排查案例
问题描述
应用出现线程死锁,需要排查死锁问题。
排查步骤
-
生成线程转储文件
bash# 使用 jstack 生成线程转储 jstack 12345 > threaddump.txt
-
分析线程转储文件
bash# 查看死锁信息 grep -A 20 "Found Java-level deadlock" threaddump.txt
-
定位死锁代码
- 分析死锁的线程
- 查看锁的获取顺序
- 修改代码避免死锁
解决方案
java
// 问题代码 - 可能导致死锁
public void method1() {
synchronized (lock1) {
synchronized (lock2) {
// 业务逻辑
}
}
}
public void method2() {
synchronized (lock2) {
synchronized (lock1) {
// 业务逻辑
}
}
}
// 优化后代码 - 避免死锁
public void method1() {
synchronized (lock1) {
synchronized (lock2) {
// 业务逻辑
}
}
}
public void method2() {
synchronized (lock1) { // 保持相同的锁顺序
synchronized (lock2) {
// 业务逻辑
}
}
}
总结
JVM 线上调优关键要点
- 监控先行:先监控再调优,基于数据做决策
- 参数调优:合理设置内存、GC 等参数
- 问题排查:掌握各种排查工具和方法
- 持续优化:持续监控和优化性能
常用调优参数总结
bash
# 生产环境推荐配置
-Xms4g -Xmx4g -Xmn2g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/heapdump.hprof
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:/path/to/gc.log
排查工具总结
- jps:查看 Java 进程
- jstat:监控 JVM 统计信息
- jmap:生成堆转储文件
- jstack:生成线程转储文件
- jinfo:查看和修改 JVM 参数
- jcmd:综合诊断命令
通过掌握这些调优命令和排查方法,可以有效地解决 JVM 线上问题,提高应用性能和稳定性。
第八章:命令速查表
8.1 进程管理命令
jps - Java 进程查看
bash
# 列出所有 Java 进程
jps
# 列出所有 Java 进程的详细信息
jps -l
# 列出所有 Java 进程的完整信息
jps -v
# 列出所有 Java 进程的完整信息
jps -m
jinfo - JVM 参数查看和修改
bash
# 查看 JVM 参数
jinfo <pid>
# 查看特定 JVM 参数
jinfo -flag MaxHeapSize <pid>
# 动态修改 JVM 参数
jinfo -flag +PrintGC <pid>
8.2 内存监控命令
jstat - JVM 统计信息监控
bash
# 监控 GC 情况
jstat -gc <pid> 1s
# 监控 GC 详细情况
jstat -gcutil <pid> 1s
# 监控类加载情况
jstat -class <pid> 1s
# 监控编译情况
jstat -compiler <pid> 1s
# 监控内存使用情况
jstat -gccapacity <pid> 1s
jmap - 内存映射和堆转储
bash
# 生成堆转储文件
jmap -dump:format=b,file=heapdump.hprof <pid>
# 查看堆内存使用情况
jmap -histo <pid>
# 查看堆内存使用情况(详细)
jmap -histo:live <pid>
# 查看类加载器信息
jmap -clstats <pid>
# 查看堆内存使用情况
jmap -heap <pid>
8.3 线程监控命令
jstack - 线程转储
bash
# 生成线程转储文件
jstack <pid> > threaddump.txt
# 生成线程转储文件(包含锁信息)
jstack -l <pid> > threaddump.txt
# 生成线程转储文件(包含本地变量)
jstack -F <pid> > threaddump.txt
8.4 综合诊断命令
jcmd - 综合诊断工具
bash
# 列出所有可用的命令
jcmd <pid> help
# 生成堆转储文件
jcmd <pid> GC.run_finalization
# 生成线程转储文件
jcmd <pid> Thread.print
# 生成类直方图
jcmd <pid> GC.class_histogram
# 查看 JVM 参数
jcmd <pid> VM.flags
# 查看系统属性
jcmd <pid> VM.system_properties
# 查看命令行参数
jcmd <pid> VM.command_line
# 查看 JVM 版本信息
jcmd <pid> VM.version
# 查看 JVM 启动时间
jcmd <pid> VM.uptime
8.5 常用排查命令组合
快速诊断
bash
# 获取进程信息
jps -l
# 查看 JVM 参数
jinfo <pid>
# 监控内存使用
jstat -gc <pid> 1s 5
# 查看线程状态
jstack <pid> | grep "java.lang.Thread.State" | sort | uniq -c
深度诊断
bash
# 生成堆转储
jmap -dump:format=b,file=heapdump.hprof <pid>
# 生成线程转储
jstack <pid> > threaddump.txt
# 生成类直方图
jmap -histo:live <pid> > class_histogram.txt
# 查看 GC 信息
jstat -gc <pid> 1s 10 > gc_info.txt
第九章:监控脚本
9.1 内存监控脚本
bash
#!/bin/bash
PID=$1
while true; do
echo "=== $(date) ==="
jstat -gc $PID 1s 1
echo ""
sleep 5
done
9.2 GC 监控脚本
bash
#!/bin/bash
PID=$1
while true; do
echo "=== $(date) ==="
jstat -gcutil $PID 1s 1
echo ""
sleep 10
done
9.3 线程监控脚本
bash
#!/bin/bash
PID=$1
while true; do
echo "=== $(date) ==="
jstack $PID | grep "java.lang.Thread.State" | sort | uniq -c
echo ""
sleep 30
done
9.4 综合监控脚本
bash
#!/bin/bash
PID=$1
LOG_DIR="/var/log/jvm-monitor"
mkdir -p $LOG_DIR
while true; do
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
echo "=== JVM 监控报告 - $TIMESTAMP ===" >> $LOG_DIR/jvm_monitor.log
# 内存使用情况
echo "--- 内存使用情况 ---" >> $LOG_DIR/jvm_monitor.log
jstat -gc $PID 1s 1 >> $LOG_DIR/jvm_monitor.log
# 线程状态
echo "--- 线程状态 ---" >> $LOG_DIR/jvm_monitor.log
jstack $PID | grep "java.lang.Thread.State" | sort | uniq -c >> $LOG_DIR/jvm_monitor.log
# 类加载情况
echo "--- 类加载情况 ---" >> $LOG_DIR/jvm_monitor.log
jstat -class $PID 1s 1 >> $LOG_DIR/jvm_monitor.log
echo "" >> $LOG_DIR/jvm_monitor.log
sleep 60
done
第十章:生产环境配置
10.1 基础配置
bash
# 内存配置
-Xms4g -Xmx4g -Xmn2g
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m
# GC 配置
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSize=16m
# 监控配置
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/heapdump.hprof
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:/path/to/gc.log
10.2 高并发配置
bash
# 内存配置
-Xms8g -Xmx8g -Xmn4g
-XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1g
# GC 配置
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100
-XX:G1HeapRegionSize=32m
-XX:ConcGCThreads=8
# 性能配置
-XX:+UseCompressedOops
-XX:+UseCompressedClassPointers
-XX:+TieredCompilation
10.3 内存受限配置
bash
# 内存配置
-Xms1g -Xmx2g -Xmn512m
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m
# GC 配置
-XX:+UseG1GC
-XX:MaxGCPauseMillis=300
-XX:G1HeapRegionSize=8m
# 优化配置
-XX:+UseCompressedOops
-XX:+AggressiveOpts
10.4 微服务配置
bash
# 内存配置
-Xms512m -Xmx1g -Xmn256m
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m
# GC 配置
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSize=8m
# 监控配置
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/heapdump.hprof
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:/tmp/gc.log
10.5 大数据处理配置
bash
# 内存配置
-Xms16g -Xmx32g -Xmn8g
-XX:MetaspaceSize=1g -XX:MaxMetaspaceSize=2g
# GC 配置
-XX:+UseG1GC
-XX:MaxGCPauseMillis=500
-XX:G1HeapRegionSize=64m
-XX:ConcGCThreads=16
# 性能配置
-XX:+UseCompressedOops
-XX:+UseCompressedClassPointers
-XX:+TieredCompilation
-XX:+AggressiveOpts
10.6 配置选择指南
根据应用类型选择配置
- Web 应用:使用基础配置或高并发配置
- 微服务:使用微服务配置
- 大数据处理:使用大数据处理配置
- 内存受限环境:使用内存受限配置
根据硬件资源选择配置
- 8GB 内存:使用基础配置
- 16GB 内存:使用高并发配置
- 32GB+ 内存:使用大数据处理配置
- 4GB 以下内存:使用内存受限配置
根据性能要求选择配置
- 低延迟要求:使用 G1 GC,设置较小的停顿时间
- 高吞吐量要求:使用 Parallel GC
- 平衡性能:使用 G1 GC,设置适中的停顿时间
注意事项
- 权限要求:某些命令需要与目标进程相同的用户权限
- 性能影响:频繁使用监控命令可能影响应用性能
- 文件大小:堆转储文件可能很大,注意磁盘空间
- 版本兼容:不同 JDK 版本的命令参数可能不同
- 生产环境:在生产环境使用时要谨慎,避免影响业务
- 监控频率:监控频率不宜过高,避免影响应用性能
- 日志管理:定期清理监控日志,避免磁盘空间不足
- 参数调优:调优参数时要逐步调整,避免一次性大幅修改
记住:JVM 调优是一个持续的过程,需要根据实际应用情况进行调整和优化。在生产环境中,建议先在测试环境验证调优效果,然后再应用到生产环境。