JVM 学习路线与故障排查
面向运维工程师的 JVM 学习路线,从内存结构到线上故障排查,循序渐进。 核心聚焦:内存模型、参数配置、监控指标、GC 日志、故障排查、线上调优、常见OOM/卡顿问题。
一、整体学习路线(由浅到深,按优先级排序)
- JVM 内存结构(运行时数据区)
- 堆内存划分 + 分代模型(新生代/老年代/元空间)
- 常见垃圾收集器、GC 算法、GC 日志解读
- 核心 JVM 启动参数(生产必配)
- 线上监控工具 & 排查命令(
jps/jstat/jmap/jhat/jstack/jinfo) - 线上典型故障:OOM、内存泄漏、CPU 飙升、线程死锁、应用卡顿
- 堆转储 dump 分析、MAT 工具使用
- 线上常规调优思路(非极致性能调优)
- 容器环境下 JVM 坑(Docker + JVM 内存限制)
二、分模块详细学习内容(运维重点标注)
一、JVM 运行时数据区(必学,理解内存从哪来)
1. 五大区域作用 + 线程私有/共享
- 程序计数器(线程私有):记录当前执行行号,唯一无 OOM 区域
- 虚拟机栈 / 本地方法栈(线程私有):方法调用、栈帧,对应 栈溢出 StackOverflowError
- 堆 Heap(线程共享):所有对象实例、数组存放地,运维 80% 问题都出在这里
- 方法区 / 元空间 Metaspace(线程共享):类元数据、常量、方法信息;JDK8 彻底移除永久代,改用元空间(直接使用宿主机物理内存)
运维关注点
- 区分:栈内存溢出 vs 堆内存溢出 现象不同、排查方向不同
- 元空间溢出场景:动态生成类、热部署、大量反射、CGLIB 代理
二、堆内存分代模型(重中之重,GC 基础)
1. 分代划分(JDK8 默认)
- 新生代 Young
- Eden 伊甸区
- Survivor 幸存区:S0 / S1(又称 From / To,永远一块空、一块用)
- 对象特点:生命周期短、回收频繁
- 老年代 Old
- 存放长期存活对象、大对象
- 回收频率低、速度慢
2. 对象流转规则(面试+排查必背)
- 新对象优先分配在 Eden
- Eden 满 → 触发 Minor GC(新生代GC)
- 存活对象进入 Survivor,年龄 +1
- 对象年龄达到阈值(默认15)→ 晋升老年代
- 大对象直接进入老年代(避免新生代复制开销)
- 老年代空间不足 → 触发 Major GC / Full GC
运维关注点
- 频繁 Minor GC、频繁 Full GC 分别代表什么问题
- 动态年龄判断、对象动态晋升规则(了解即可)
- 大对象直接进老年代带来的隐患
三、垃圾回收 GC 算法 & 垃圾收集器(核心)
1. 基础 GC 算法(理解原理,不用手写)
- 标记-清除:产生内存碎片
- 复制算法:新生代主流,无碎片,占用双倍空间
- 标记-整理:老年代主流,压缩整理,无碎片
2. 主流垃圾收集器(运维只记特点、适用场景、搭配)
按使用频率排序:
- G1(Garbage-First)
- JDK9+ 默认,JDK8 生产首选
- 整堆分区划分,可预测停顿时间
- 兼顾吞吐量 + 低延迟,线上业务服务标配
- Parallel GC(Parallel Scavenge + Parallel Old)
- JDK8 默认,侧重吞吐量
- 适合:后台批处理、报表、离线任务,对停顿不敏感
- CMS(Concurrent Mark Sweep)
- 并发低延迟,老年代收集器
- 缺点:内存碎片、并发浮动垃圾、CPU 占用高
- 现在逐步被 G1 替代
- ZGC / Shenandoah(低延迟神器)
- JDK11+ 新收集器,毫秒级停顿
- 高并发、低延迟核心服务使用
运维必须掌握
- 区分:Minor GC / Major GC / Full GC 触发条件 & 影响
- GC 日志解读(线上排障第一手依据)
- 看懂:内存使用、回收前后大小、停顿时间、GC 类型
- 不同收集器对应的日志格式差异
四、JVM 核心启动参数(生产必背、日常配置)
分三类:内存参数、GC参数、排查辅助参数
1. 内存相关(最常用)
# 堆初始内存、最大堆内存
-Xms # 初始堆,生产建议 = -Xmx,避免运行期扩容卡顿
-Xmx # 最大堆内存
# 新生代大小 / 比例
-Xmn # 新生代总大小
-XX:SurvivorRatio # Eden / Survivor 比例
# 元空间(JDK8+)
-XX:MetaspaceSize
-XX:MaxMetaspaceSize
# 栈内存
-Xss # 单个线程栈大小
# 大对象阈值
-XX:PretenureSizeThreshold
2. GC 收集器指定
# G1 开启
-XX:+UseG1GC
# 并行收集器(JDK8默认)
-XX:+UseParallelGC
# CMS
-XX:+UseConcMarkSweepGC
3. 故障排查必备参数(生产强制加上)
# 打印GC详细日志
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
# OOM 时自动生成堆转储文件(最重要!)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/xxx/heap.hprof
# OOM 执行脚本(可选,发告警、重启)
-XX:OnOutOfMemoryError="sh /xxx/restart.sh"
运维底线:所有 Java 应用必须开启 OOM dump + GC 日志
五、线上排查命令集(运维每日在用,必须熟练)
1. 基础进程查看
jps:查看 Java 进程、PID、启动参数jinfo pid:查看/动态修改 JVM 参数
2. 实时监控 GC & 内存
jstat -gc pid 1000:每秒打印GC统计(线上首选,轻量不影响性能)
重点看:YGC、YGCT、FGC、FGCT、堆各区域使用率
3. 线程排查(CPU 高、卡顿、死锁)
-
jstack pid:打印线程栈
用途: -
线程死锁
-
死循环导致 CPU 100%
-
线程阻塞、任务堆积
4. 堆内存快照(OOM、内存泄漏)
jmap -dump:format=b,file=xxx.hprof pid:手动生成堆dumpjmap -heap pid:查看当前堆配置、各代使用情况
5. 分析工具
- MAT(Memory Analyzer Tool):解析 hprof 文件,找大对象、内存泄漏、可疑类
- JVisualVM:图形化监控、远程连接、抽样分析
运维标准排查流程(背下来)
top/htop找到高 CPU / 高内存 Java PIDjstat观察 GC 频率,判断是频繁GC还是内存溢出jstack查线程:死锁、死循环、阻塞- 若怀疑内存泄漏/OOM:分析 GC 日志 + 下载 heap.hprof 用 MAT 分析
六、线上高频故障(运维核心考点,场景+现象+原因+处理)
1. 内存溢出 OOM(java.lang.OutOfMemoryError)
细分 4 种常见类型:
- Java heap space 堆溢出
- 现象:老年代占满,Full GC 频繁且回收效果差
- 原因:内存泄漏、堆太小、业务峰值流量大
- Metaspace 元空间溢出
- 原因:动态类、热部署、大量反射、动态代理
- Unable to create new native thread 无法创建新线程
- 原因:线程数打满、单个栈-Xss设置过大、系统线程数上限低
- GC overhead limit exceeded
- JVM 花 98% 时间 GC,只回收 2% 内存,直接报错退出
- 典型:严重内存泄漏
2. 应用卡顿、响应慢
- 现象:接口超时、RT 飙升、吞吐量下降
- 根因:
- 频繁 Full GC / CMS GC 停顿
- 大量线程阻塞、锁等待
- 死循环 CPU 跑满
3. CPU 占用 100%
排查步骤:
- top 找到 PID
top -Hp pid找到高占用线程 TID- TID 转十六进制
jstack pid | grep 十六进制TID定位死循环代码行
4. 内存泄漏(最隐蔽)
- 现象:内存缓慢上涨,Full GC 越来越频繁,最终 OOM
- 排查:GC 日志 + heap dump + MAT 找无法被回收的大对象
5. 线程死锁
- 现象:服务卡住、请求不返回、线程池耗尽
- 排查:
jstack直接搜索Deadlock
七、容器环境 JVM 专属坑(现在运维必学:Docker + Java)
经典问题
Docker 内部 Java 进程识别宿主机全量内存,不识别容器内存限制,导致:
- 容器被 OOM kill(内核杀死进程)
- JVM 堆设太大,超出容器限额
解决方案
- JDK8 u191+ / JDK10+ 支持容器内存感知
- 启动参数增加:
-XX:+UnlockExperimentalVMOptions
-XX:+UseCGroupMemoryLimitForHeap
- 规范:容器内
-Xmx一定要小于容器 memory limit,预留系统/堆外/元空间/栈内存
八、运维 vs 开发 JVM 学习边界(分清重点,不做无用功)
✅ 运维必须深耕
- 内存分区、分代模型
- GC 类型、收集器特点、GC 日志解读
- 全套
jps/jstat/jmap/jstack命令实操 - OOM、内存泄漏、CPU高、死锁 全套排查流程
- 生产 JVM 参数配置、调优思路
- Docker + JVM 适配问题
- MAT 分析堆快照
❌ 运维简单了解即可(不用深挖)
- 类加载器双亲委派模型(知道概念就行,不用源码)
- 字节码、指令集、javac 编译
- JIT 即时编译底层、逃逸分析(了解概念)
- 各种 GC 算法数学推导、收集器源码
九、学习顺序建议(循序渐进)
- 先搞懂 运行时数据区 → 知道内存分哪几块
- 再学 堆分代 + 对象流转 → 理解 GC 为什么发生
- 掌握 GC 收集器选型 + GC 日志
- 熟记 常用 JVM 参数,能独立编写启动脚本
- 练熟 jps/jstat/jmap/jstack 四大命令,模拟排障
- 学习 MAT 分析 dump 文件
- 逐个吃透线上经典故障场景
- 补充 Docker + JVM 容器坑
- 简单了解调优思路(非开发级深度调优)
十、面试高频 JVM 题(运维岗)
- 简述 JVM 运行时数据区,哪些线程共享、哪些私有?
- 新生代、老年代 GC 分别是什么?触发条件?
- G1 和 Parallel、CMS 收集器区别,生产如何选型?
- 线上应用频繁 Full GC 怎么排查?
- 发生 OOM 你如何一步步定位问题?
- CPU 100% 如何排查?
- 内存泄漏和内存溢出区别?怎么排查内存泄漏?
- Docker 中部署 Java 应用有哪些 JVM 坑?如何解决?
关联文档