JVM 核心知识
写 Java 代码久了,很多同学会忽略一个根本问题:你的代码到底是怎么在 JVM 上跑的?
JVM 是 Java 区别于其他语言的核心差异之一。C++ 需要手动管理内存,Python 有 GC 但无法调优,而 Java 给了我们一个可观测、可调优、可控制的运行时环境。但这个能力的前提是——你得理解 JVM 怎么工作的。
我自己踩过 JVM 的坑:有一次线上服务频繁 Full GC,内存不断飙升,排查了三个小时才发现是 HashMap 没有预设容量导致扩容触发了大量对象创建,年轻代迅速填满后触发了 Old GC。
这套内容,就是帮你把 JVM 从里到外全部搞明白。
内容总览
JVM 知识可以分成三大块:
知识全景
运行时数据区 🔴
JVM 运行时数据区 — 堆/方法区/栈/PC 寄存器/直接内存的全景图
堆内存分代(新生代/老年代/元空间) — Eden/S0/S1/Old Gen/Metaspace 的分工
栈帧结构(局部变量表/操作数栈) — 方法调用时栈里到底装了什么
对象内存布局(对象头/实例数据/对齐填充) — 一个对象在内存里长什么样
对象创建流程 — 从 new 到构造函数执行的全过程
逃逸分析与栈上分配 — JIT 怎么通过逃逸分析做性能优化
JDK 8 之后,永久代(PermGen)被元空间(Metaspace)替代。元空间使用本地内存,不再受 -Xmx 堆大小限制。但这不意味着可以无限加载类——MaxMetaspaceSize 仍然限制元空间大小。大量动态类生成(如 CGLib、OSGi)仍然可能导致 Metaspace OOM。
垃圾回收 🔴🔴
GC 是 JVM 里最重要也最复杂的部分。理解 GC,首先要理解"怎么判断对象已死"。
垃圾回收判定(引用计数/可达性分析) — 引用计数无法处理循环引用,可达性分析才是答案
GC Roots 有哪些 — 哪些对象可以作为 GC 的起点
四种引用类型(强/软/弱/虚) — 强引用/SoftReference/WeakReference/PhantomReference 的 GC 行为
垃圾回收算法(标记清除/复制/标记整理) — 三种基本算法的原理与 trade-off
分代收集理论 — 为什么分代是最优策略
收集器(重点):
Serial/Parallel/CMS 收集器 — Serial 单线程、Parallel 多线程、CMS 并发标记
G1 收集器原理(Region/RSet) — JDK 11+ 默认收集器,可预测停顿时间
ZGC 收集器原理(染色指针/读屏障) — 亚毫秒级停顿,停顿时间不随堆大小增长
调优相关:
GC 日志解读与分析 — 如何读懂 GC 日志,定位问题
GC 调优方法论与案例 — 怎么选择收集器、怎么调参数
GC 调优的核心思路:先诊断,再决策。不要一上来就调参数,先用 GC 日志和工具搞清楚问题是什么:频繁 Young GC → 增加年轻代;Full GC 慢 → 考虑 G1 或 ZGC;内存泄漏 → 排查堆 Dump。
类加载机制 🔴
类加载机制(加载/验证/准备/解析/初始化) — 类从 .class 文件到内存的全过程
双亲委派模型 — Bootstrap/Extension/Application 三层加载链
打破双亲委派的场景(Tomcat/SPI) — 为什么 Tomcat 每个 Webapp 要用自己的 ClassLoader
自定义类加载器实现 — 怎么写自己的 ClassLoader
OOM 与排查 🔴
内存溢出排查(OOM) — 各种 OOM 的原因与排查方法
堆转储(Heap Dump)分析 — MAT 工具的使用方法
面试关联
JVM 和其他 Java 模块紧密相连:
- 对象头/Mark Word → synchronized 锁升级、GC Roots 有哪些
- 堆内存 → ArrayList/HashMap 扩容
- GC 算法 → 垃圾收集器
- 类加载 → Spring 依赖注入、JDBC 驱动加载
阅读建议
记住:JVM 不是"调优工具箱",而是一套系统性的运行时环境。理解它的设计原理,才能在遇到问题时快速定位、在性能调优时做出正确决策。