Appearance
JVM 调优
调优基础
性能监控工具
bash
# JPS - 查看 Java 进程
jps -l
jps -v | grep heap
# JSTAT - 监控 JVM 统计信息
jstat -gcutil <pid> 1000 10 # 每秒一次,共10次
jstat -gc <pid> # 详细 GC 信息
# JMAP - 导出堆转储
jmap -dump:format=b,file=heap.hprof <pid>
jmap -heap <pid> # 堆配置和使用
# JSTACK - 打印线程堆栈
jstack <pid> > thread.log
# JINFO - 查看/修改配置
jinfo -flags <pid> # 查看所有参数
jinfo -flag MaxHeapSize <pid> # 查看某个参数常用监控命令
bash
# GC 统计
jstat -gcutil 12345 1000
# 输出示例:
# S0 S1 E O M YGC YGCT FGC FGCT GCT
# 0.00 65.00 55.00 45.00 91.00 125 0.456 3 0.125 0.581
# S0/S1 = Survivor 区使用率
# E = Eden 区使用率
# O = Old 区使用率
# M = Metaspace 使用率
# YGC = Young GC 次数
# YGCT = Young GC 总耗时(秒)
# FGC = Full GC 次数
# FGCT = Full GC 总耗时(秒)JVM 参数
常用参数
bash
# 堆内存
-Xms256m # 初始堆大小
-Xmx512m # 最大堆大小
-Xmn128m # 新生代大小
-Xss1m # 线程栈大小
-XX:MetaspaceSize=256m # 元空间初始大小
-XX:MaxMetaspaceSize=512m # 元空间最大
# 新生代
-XX:NewRatio=2 # 老年代/新生代比例 (默认2)
-XX:SurvivorRatio=8 # Eden/Survivor比例 (默认8)
# GC
-XX:+UseG1GC # 使用 G1 收集器
-XX:MaxGCPauseMillis=200 # 最大 GC 停顿时间
-XX:+PrintGCDetails # 打印 GC 详情
-XX:+PrintGCDateStamps # 打印 GC 时间戳
-Xloggc:/path/to/gc.log # GC 日志文件
# OOM 处理
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dumpJDK 8 推荐配置
bash
# 通用服务器配置
java -server \
-Xms4g -Xmx4g \
-Xmn2g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/heap.hprof \
-Xloggc:/var/log/gc.log \
-jar app.jar调优场景
场景1:Young GC 频繁
症状:
- YGC 次数很多
- YGCT 累积增长快
原因:
- Eden 区太小
- 对象分配过快
解决:
bash
# 方案1:增大 Eden 区
-Xmn512m -XX:SurvivorRatio=6
# 方案2:直接增大新生代
-Xmn1g场景2:Full GC 频繁
症状:
- Full GC 次数多
- FGCT 累积增长快
原因:
- 老年代空间不足
- 内存泄漏
- 大对象直接进入老年代
解决:
bash
# 方案1:检查内存泄漏
jmap -histo <pid> | head -30 # 查看对象分布
# 方案2:调整大对象阈值
-XX:PretenureSizeThreshold=2m # 超过2m直接进老年代
# 方案3:增大老年代
-Xms4g -Xmx4g -Xmn1g # 老年代 3g场景3:GC 停顿时间过长
症状:
- 用户请求响应慢
- GC 日志显示 STW 时间长
原因:
- 堆太大
- G1 Region 太多
解决:
bash
# 方案1:减小堆大小(并行 GC 场景)
-Xms2g -Xmx2g
# 方案2:调整 G1 参数
-XX:MaxGCPauseMillis=100 # 目标停顿时间
-XX:G1HeapRegionSize=16m # Region 大小
-XX:ConcGCThreads=4 # 并发 GC 线程数OOM 问题排查
步骤
┌─────────────────────────────────────────────────────────────────┐
│ OOM 排查流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 配置 JVM 参数保留堆 dump │
│ -XX:+HeapDumpOnOutOfMemoryError │
│ -XX:HeapDumpPath=/path/to/dump.hprof │
│ │
│ 2. 重现问题,生成 dump 文件 │
│ │
│ 3. 使用 MAT 分析 dump │
│ - Histogram: 按对象数量/大小排序 │
│ - Dominator Tree: 对象引用关系 │
│ - Top Consumers: 最大的对象 │
│ │
│ 4. 定位问题代码 │
│ │
└─────────────────────────────────────────────────────────────────┘MAT 使用
bash
# 启动 MAT
mat64.sh heap.hprof
# 常见分析视图:
# - Histogram: 按类统计对象
# - Dominator Tree: 支配树,找 GC Root 引用链
# - Top Consumers: 内存消耗最大的对象/类
# - Leak Suspects: 可疑的内存泄漏常见 OOM 原因
| OOM 类型 | 原因 | 解决方案 |
|---|---|---|
| Java heap space | 对象太多 | 增大堆,检查内存泄漏 |
| GC overhead limit | GC 太频繁 | 减少对象创建,优化代码 |
| Metaspace | 类太多 | 增大元空间,检查 CGLib |
| Direct buffer | NIO 直接内存 | 限制大小 |
| Unable to create native thread | 线程太多 | 减少线程数 |
Arthas 工具
常用命令
bash
# 启动 Arthas
java -jar arthas-boot.jar
# 监控方法调用
watch com.example.UserService getUser "{params, returnObj}"
# 查看方法耗时
trace com.example.UserService getUser
# 查看线程状态
thread
# 查看加载的类
sc com.example.*
# 反编译类
jad com.example.UserService总结
JVM 调优核心知识点:
| 知识点 | 面试频率 | 实战重要性 |
|---|---|---|
| JVM 监控工具 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| JVM 参数配置 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| GC 日志分析 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| OOM 排查 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
⚠️ 易错点提醒:
- 不是所有问题都需要调优,先用工具定位问题
- G1 不是万能的,小内存用 CMS,大内存用 G1
- 线上环境不要用 -Xms == -Xmx(固定大小更好)
- 内存泄漏排查用 MAT,循环依赖用 MAT Dominator Tree
- GC 日志是排查 GC 问题的第一手资料