这是《JVM 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 本附录汇总本书常用命令、参数和排查路径,便于日常快速查阅。不同 JDK 版本和发行版的行为可能不同,生产使用前应以当前运行时输出和官方文档为准。
1. 常用命令
进程与基本信息
# 查看 Java 进程
jps -l
# 查看系统进程
ps -ef | grep java
# 查看 JVM 启动参数
jcmd <pid> VM.command_line
# 查看最终 flags
jcmd <pid> VM.flags
# 查看所有 flags
java -XX:+PrintFlagsFinal -version
内存与 GC
# 堆信息
jcmd <pid> GC.heap_info
# GC 概览
jstat -gc <pid> 1000
jstat -gcutil <pid> 1000
# 类直方图,可能开销较大
jcmd <pid> GC.class_histogram
# 手动堆 dump
jcmd <pid> GC.heap_dump /data/dump/app.hprof
# 触发 Full GC,慎用
jcmd <pid> GC.run
线程与诊断
# 线程 dump
jcmd <pid> Thread.print > thread-1.txt
jstack <pid> > thread-1.txt
# 连续采集
for i in 1 2 3 4 5; do
jcmd <pid> Thread.print > "thread-$i.txt"
sleep 2
done
# JFR
jcmd <pid> JFR.check
jcmd <pid> JFR.start name=live settings=profile filename=/log/live.jfr maxsize=512m
jcmd <pid> JFR.dump name=live filename=/log/now.jfr
jcmd <pid> JFR.stop name=live
Linux 排查
# 进程 CPU
top -p <pid>
# 线程 CPU
top -H -p <pid>
ps -L -p <pid> -o pid,tid,%cpu,%mem,state,comm --sort=-%cpu
# 十进制线程号转十六进制
printf "%x\n" <tid>
# 系统指标
vmstat 1
pidstat -p <pid> -t 1
iostat -x 1
2. 常用 JVM 参数
内存
| 参数 | 用途 |
|---|---|
-Xms |
初始堆 |
-Xmx |
最大堆 |
-Xmn |
新生代 |
-Xss |
线程栈 |
-XX:NewRatio |
Old 与 New 比例 |
-XX:SurvivorRatio |
Eden 与 Survivor 比例 |
-XX:MaxMetaspaceSize |
元空间上限 |
-XX:MaxDirectMemorySize |
直接内存上限 |
-XX:SoftMaxHeapSize |
ZGC 等软堆目标 |
收集器
-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+UseG1GC
-XX:+UseZGC
-XX:+UseShenandoahGC # 需运行时支持
-XX:MaxGCPauseMillis=50
CMS 相关:
| JDK | 状态 |
|---|---|
| JDK 8 | 可用 |
| JDK 9 | deprecated |
| JDK 14 | 移除 |
容器
-XX:+UseContainerSupport
-XX:InitialRAMPercentage=60.0
-XX:MaxRAMPercentage=60.0
-XX:MinRAMPercentage=50.0
-XX:ActiveProcessorCount=4
容器内存预算:
容器 limit
>= Heap
+ Metaspace
+ Thread stacks
+ Direct memory
+ CodeCache
+ Native memory
+ OS 余量
3. 日志配置
现代 JDK:
java -Xlog:gc*,safepoint:file=/logs/gc.log:time,uptime,level,tags:filecount=10,filesize=50m \
-jar app.jar
JDK 8:
java -XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-XX:+PrintTenuringDistribution \
-Xloggc:/logs/gc.log \
-XX:+UseGCLogFileRotation \
-XX:NumberOfGCLogFiles=10 \
-XX:GCLogFileSize=50M \
-jar app.jar
OOM 证据:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/dump
-XX:+ExitOnOutOfMemoryError
4. 工具速查
| 工具 | 用途 |
|---|---|
javap |
查看字节码 |
jstat |
GC 统计 |
jmap |
堆信息与 dump |
jcmd |
推荐 JVM 命令入口 |
jstack |
线程 dump |
jhsdb |
调试服务 |
jfr |
查看 JFR 事件 |
| MAT | 堆 dump 分析 |
| JMC | JFR 可视化 |
| Arthas | 在线诊断 |
| GCEasy / GCViewer | GC 日志可视化 |
| async-profiler | CPU 与分配采样 |
5. 字节码命令
# 编译
javac -g Demo.java
# 查看字节码
javap -c Demo.class
# 查看常量池和详细信息
javap -v Demo.class
# 查看私有成员
javap -p Demo.class
常见指令:
| 指令 | 含义 |
|---|---|
aload_0 |
加载 this |
iload_1 |
加载第 1 个 int 参数 |
istore_1 |
保存 int 到局部变量 |
invokevirtual |
调用虚方法 |
invokespecial |
构造、private、super |
invokestatic |
调用静态方法 |
invokeinterface |
调用接口方法 |
invokedynamic |
Lambda、字符串拼接等动态调用 |
new |
创建对象 |
monitorenter |
进入 monitor |
monitorexit |
退出 monitor |
6. 线程状态
| 状态 | 含义 |
|---|---|
| NEW | 尚未启动 |
| RUNNABLE | 可运行,可能等待 CPU 或 Native IO |
| BLOCKED | 等待 monitor |
| WAITING | 无限期等待 |
| TIMED_WAITING | 限时等待 |
| TERMINATED | 结束 |
死锁特征:
thread A waiting to lock L1, held by B
thread B waiting to lock L2, held by A
处理方向:统一加锁顺序、缩小锁范围、tryLock 超时、拆分锁粒度、避免锁内 IO。
7. GC 选择速查
| 场景 | 起点 |
|---|---|
| 小内存、低并发 | Serial |
| 批处理、吞吐优先 | Parallel |
| 常见在线服务 | G1 |
| 大堆、低停顿、资源充足 | ZGC |
| 发行版支持且压测通过 | Shenandoah |
G1 关键点:
Region 化堆
Young / Mixed / Full GC
Remembered Set
可设置停顿目标
ZGC 关键点:
着色指针
读屏障
并发整理
Allocation Stall
JDK 21 分代模式
8. OOM 类型速查
| 类型 | 方向 |
|---|---|
| Java heap space | 堆 dump、GC 日志、对象泄漏 |
| GC overhead limit exceeded | 存活对象高、堆余量不足 |
| Metaspace | 类加载器、动态类生成 |
| Unable to create new native thread | 线程数、栈大小、OS 限制 |
| Direct buffer memory | NIO、Netty、直接内存 |
| Requested array size exceeds VM limit | 超大数组 |
| OOMKilled / exit 137 | 容器总内存超限 |
应急流程:
摘流量
-> 保存日志和 dump
-> 记录监控和事件
-> 重启或替换
-> 分析根因
-> 灰度验证
9. CPU 高排查
1. top 判断 user/sys/iowait
2. top -H 找高 CPU 线程
3. printf 转十六进制
4. 线程 dump 搜索 nid
5. 判断业务 / GC / JIT 线程
6. JFR 或 Arthas 定位方法
7. 结合流量和数据特征
8. 修复后压测验证
Arthas:
dashboard
thread -n 5
thread -b
trace com.demo.Service method '#cost > 100' -n 10
watch com.demo.Service method params returnObj throwExp -x 2 -n 5
stack com.demo.Service method -n 5
stop
10. 内存泄漏常见来源
| 来源 | 特征 |
|---|---|
| 静态集合 | Retained Heap 大且持续增长 |
| ThreadLocal | 线程池线程持有 |
| 监听器 | 未注销 |
| 无界缓存 | key 持续增长 |
| 大查询 | byte[]、ArrayList、String 巨大 |
| ClassLoader | 同名类大量重复加载 |
| 队列积压 | 生产快于消费 |
MAT 关键视图:
Histogram
Dominator Tree
Path to GC Roots
Leak Suspects
Thread Overview
重点指标:
Shallow Heap:对象自身大小
Retained Heap:回收该对象可释放总量
11. JFR 模板
启动时:
java -XX:StartFlightRecording=filename=/logs/app.jfr,settings=profile,maxsize=1g,maxage=6h,dumponexit=true \
-jar app.jar
告警后:
jcmd <pid> JFR.dump name=<recording> filename=/logs/incident.jfr
看什么:
CPU Load
Execution Sample
Allocation Sample
Java Monitor Blocked
Thread Park
Garbage Collection
Safepoint
Exception Statistics
12. 容器检查清单
1. memory request 与 limit
2. CPU request 与 limit
3. -Xmx 或 MaxRAMPercentage
4. MaxMetaspaceSize
5. MaxDirectMemorySize
6. 线程数和 -Xss
7. ActiveProcessorCount
8. GC 日志目录挂载
9. dump 目录挂载
10. Java 进程能收到 SIGTERM
11. 优雅停机时间小于 terminationGracePeriodSeconds
12. 健康检查和就绪检查
推荐启动模板:
exec java \
-XX:+UseContainerSupport \
-XX:InitialRAMPercentage=60.0 \
-XX:MaxRAMPercentage=60.0 \
-XX:ActiveProcessorCount=4 \
-XX:MaxMetaspaceSize=512m \
-XX:MaxDirectMemorySize=1g \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/data/dump \
-XX:+ExitOnOutOfMemoryError \
-Xlog:gc*,safepoint:file=/logs/gc.log:time,uptime,level,tags:filecount=10,filesize=50m \
-XX:StartFlightRecording=filename=/logs/app.jfr,settings=profile,maxsize=512m,maxage=6h,dumponexit=true \
-jar /app/app.jar
13. 监控指标
必须监控:
process_cpu
container_cpu_usage
container_cpu_throttling
container_memory_usage
jvm_heap_used
jvm_heap_committed
jvm_heap_max
jvm_gc_pause
jvm_gc_count
jvm_gc_time
jvm_metaspace
jvm_direct_memory
jvm_thread_count
jvm_class_loaded
safepoint_time
http_p50
http_p99
http_p999
error_rate
建议告警:
| 指标 | 方向 |
|---|---|
| Full GC | 大于 0 需关注 |
| GC P99 | 超过延迟目标 |
| Allocation Stall | 大于 0 |
| 回收后 Old | 持续增长 |
| memory usage / limit | 大于 85% |
| CPU throttling | 持续增长 |
| 线程数 | 突增或接近上限 |
| 重启次数 | 异常增长 |
14. 排障模板
时间:
实例:
版本:
现象:
系统指标:
CPU =
Memory =
Disk =
Network =
JVM:
Heap =
GC =
Threads =
Metaspace =
Direct memory =
证据:
GC log =
Thread dump =
Heap dump =
JFR =
Business log =
分析:
1.
2.
3.
根因:
修复:
验证:
预防:
15. 版本提醒
| 主题 | 重要差异 |
|---|---|
| 永久代 | JDK 8 移除,使用 Metaspace |
| CMS | JDK 14 移除 |
| 偏向锁 | JDK 15 起 deprecated |
| ZGC | JDK 15 转正,JDK 21 引入分代 |
| 虚拟线程 | JDK 21 正式发布 |
| JFR | JDK 11 后开源并广泛可用 |
升级或迁移时,应重新压测,而不是假设参数和默认值完全兼容。
16. 快速判断表
| 现象 | 优先检查 |
|---|---|
| OOM heap | dump、GC 日志、大对象 |
| OOMKilled | 容器总内存、堆外 |
| CPU user 高 | 线程栈、JFR 热点 |
| CPU sys 高 | 上下文切换、锁、系统调用 |
| GC 停顿高 | 收集器、堆、Live 数据 |
| 安全点等待高 | 长循环、大数组操作 |
| 线程 BLOCKED | 锁持有者、临界区 |
| 线程池满 | 外部超时、队列、下游 |
| 启动慢 | JIT、类加载、CPU limit |
| 延迟毛刺 | CPU throttling、GC、安全点 |