第六章:JVM 调优实战 ------ GC日志分析、内存溢出排查与线上问题定位
本章目标
- 掌握 JVM 线上问题排查思路
- 学会分析 GC 日志
- 学会定位 OOM(内存溢出)
- 掌握 jps、jstat、jmap、jstack 等工具
- 学会分析 Heap Dump
- 掌握生产环境 JVM 调优方法
一、为什么要学习 JVM 调优?
很多开发者学习 JVM 时:
知道GC原理
知道G1
知道ZGC
但到了线上:
sql
CPU 100%
频繁Full GC
接口超时
服务卡死
OOM
却不知道如何排查。
实际上:
面试中的 JVM
关注:
GC算法
垃圾收集器
JMM
工作中的 JVM
关注:
sql
为什么Full GC?
为什么OOM?
为什么CPU飙高?
为什么接口变慢?
真正值钱的是:
线上问题排查能力
二、JVM 调优核心原则
先记住一句话:
没有最优参数
只有最适合业务的参数
例如:
电商系统:
低延迟优先
推荐:
G1
ZGC
批处理系统:
吞吐量优先
推荐:
Parallel GC
三、线上排查第一步:确认 JVM 进程
查看 Java 进程:
jps -l
输出:
12345 com.company.OrderApplication
67890 Jps
说明:
12345
就是目标进程 PID。
四、查看 JVM 基本信息
查看启动参数:
jinfo 12345
查看:
diff
-Xms
-Xmx
GC配置
系统属性
查看 JVM 状态:
yaml
jstat -gc 12345 1000
每秒输出一次:
S0C
S1C
EC
OC
YGC
FGC
五、GC日志是什么?
GC 日志记录:
什么时候GC
回收了多少内存
暂停了多久
例如:
csharp
[GC pause (G1 Evacuation Pause)
200M->50M(1024M)
10ms]
含义:
GC前:200M
GC后:50M
总堆:1024M
耗时:10ms
六、开启 GC 日志
JDK8:
ruby
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:gc.log
JDK9+:
ruby
-Xlog:gc*:file=gc.log
生成:
c
gc.log
七、GC日志怎么看?
示例:
csharp
[GC (Allocation Failure)
256M->32M(512M),
0.010s]
分析:
256M
GC前使用
32M
GC后使用
512M
总堆大小
10ms
GC耗时
重点关注:
sql
GC频率
GC耗时
Full GC次数
八、什么样的GC是健康的?
例如:
每分钟Minor GC几次
正常。
如果:
每秒Minor GC
说明:
对象创建过快
如果:
sql
频繁Full GC
通常:
内存配置不合理
或者:
内存泄漏
九、GC问题排查口诀
看到频繁GC:
先问:
对象太多?
内存太小?
泄漏?
不要直接改参数。
十、线上最常见问题:OOM
经典异常:
java.lang.OutOfMemoryError
OOM并不只有一种。
十一、Heap OOM
最常见。
异常:
makefile
java.lang.OutOfMemoryError:
Java heap space
示例:
csharp
List<byte[]> list =
new ArrayList<>();
while(true){
list.add(new byte[1024*1024]);
}
持续占用堆。
最终:
Heap OOM
十二、Metaspace OOM
异常:
makefile
OutOfMemoryError:
Metaspace
常见原因:
动态生成大量类
例如:
objectivec
CGLIB
ByteBuddy
ASM
十三、栈溢出
异常:
StackOverflowError
示例:
csharp
public void test() {
test();
}
无限递归。
最终:
StackOverflowError
十四、Direct Memory OOM
异常:
arduino
Direct buffer memory
示例:
yaml
ByteBuffer.allocateDirect(
1024 * 1024);
大量创建。
常见于:
Netty
NIO
十五、OOM 排查第一步:Dump
生产环境必须开启:
ruby
-XX:+HeapDumpOnOutOfMemoryError
发生OOM:
自动生成:
heap.hprof
文件。
十六、Heap Dump 是什么?
Heap Dump:
某一时刻
整个堆内存快照
包含:
所有对象
引用关系
对象大小
十七、查看堆情况
命令:
jmap -heap PID
查看:
堆大小
GC配置
各区域使用率
查看对象统计:
jmap -histo PID
输出:
kotlin
num
instances
bytes
class name
例如:
arduino
1:
500000
40000000
java.lang.String
说明:
arduino
String过多
十八、MAT 工具分析 Dump
MAT:
Memory Analyzer Tool
JVM排查神器。
打开:
heap.hprof
重点看:
Leak Suspects
例如:
arduino
static HashMap
引用:
200万对象
立即发现问题。
十九、经典内存泄漏案例
错误代码:
swift
public class Cache {
private static final List<User>
USERS = new ArrayList<>();
}
业务不断:
csharp
USERS.add(user);
由于:
arduino
static变量
始终是 GC Root。
导致:
永远不会回收
最终:
OOM
二十、CPU 100% 如何排查?
很多线上事故:
erlang
CPU直接100%
第一步:
css
top -Hp PID
查看线程。
输出:
12345
线程ID。
转16进制:
perl
printf "%x\n" 12345
例如:
yaml
3039
二十一、查看线程堆栈
命令:
c
jstack PID > stack.log
搜索:
ini
nid=0x3039
找到问题线程。
例如:
arduino
while(true){
}
导致:
死循环
CPU100%。
二十二、死锁排查
代码:
javascript
synchronized(lock1){
synchronized(lock2){
}
}
另一个线程:
javascript
synchronized(lock2){
synchronized(lock1){
}
}
形成:
DeadLock
jstack:
jstack PID
直接输出:
sql
Found one Java-level deadlock
二十三、频繁 Full GC 排查案例
现象:
接口越来越慢
监控:
sql
Full GC
每分钟50次
jstat:
jstat -gc PID
发现:
sql
Old区一直增长
Dump分析:
css
Order对象
300万
继续分析:
vbnet
static Map<Long, Order>
缓存未清理。
解决:
Guava Cache
Redis
定时清理
问题解决。
二十四、GC 调优常见参数
设置初始堆:
diff
-Xms4g
最大堆:
diff
-Xmx4g
推荐:
ini
Xms = Xmx
避免动态扩容。
G1停顿时间:
ini
-XX:MaxGCPauseMillis=200
开启Dump:
ruby
-XX:+HeapDumpOnOutOfMemoryError
Dump路径:
ruby
-XX:HeapDumpPath=/data/dump
二十五、线上 JVM 排查流程
记住这张图。
出现问题:
服务变慢
↓
查看:
css
top
↓
CPU高?
objectivec
YES
↓
jstack
分析线程。
CPU正常?
↓
查看:
jstat -gc
分析GC。
GC频繁?
↓
jmap -histo
查看对象。
↓
MAT
分析Dump。
↓
定位泄漏对象。
二十六、面试高频题
Full GC频繁怎么办?
先看:
GC日志
再分析:
老年代对象
而不是直接调参数。
如何定位OOM?
步骤:
开启Dump
生成hprof
MAT分析
找到大对象
CPU 100% 怎么查?
步骤:
css
top
top -Hp
jstack
定位线程
jstack 有什么用?
查看:
线程状态
死锁
阻塞
MAT 最常看什么?
Leak Suspects
Dominator Tree
二十七、生产环境 JVM 参数模板
8G服务器
ruby
-server
-Xms4g
-Xmx4g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/dump
-Xlog:gc*:file=/data/logs/gc.log
本章总结
线上 JVM 排查核心思路:
objectivec
服务异常
│
▼
CPU高?
│
├── YES
│ ▼
│ jstack
│
└── NO
▼
GC频繁?
│
▼
jstat
│
▼
Full GC?
│
▼
Dump
│
▼
MAT
│
▼
找到泄漏对象
到这里,你已经掌握了 JVM 的:
- 内存结构
- GC 原理
- 垃圾收集器
- JVM 调优
- 线上故障排查