JVM 核心知识

写 Java 代码久了,很多同学会忽略一个根本问题:你的代码到底是怎么在 JVM 上跑的?

JVM 是 Java 区别于其他语言的核心差异之一。C++ 需要手动管理内存,Python 有 GC 但无法调优,而 Java 给了我们一个可观测、可调优、可控制的运行时环境。但这个能力的前提是——你得理解 JVM 怎么工作的。

我自己踩过 JVM 的坑:有一次线上服务频繁 Full GC,内存不断飙升,排查了三个小时才发现是 HashMap 没有预设容量导致扩容触发了大量对象创建,年轻代迅速填满后触发了 Old GC。

这套内容,就是帮你把 JVM 从里到外全部搞明白。

内容总览

JVM 知识可以分成三大块:

板块核心内容解决什么问题
运行时数据区堆/栈/方法区/PC 寄存器/直接内存理解对象存在哪里、内存怎么分配
垃圾回收GC 算法/收集器/调优/日志分析解决频繁 GC、Full GC 停顿过长的问题
类加载加载/验证/准备/解析/初始化/双亲委派理解类的生命周期,解决类冲突问题

知识全景

运行时数据区 🔴

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 模块紧密相连:

阅读建议

你的阶段推荐顺序
面试冲刺运行时数据区 → GC 判定 → 垃圾回收算法 → G1/ZGC → 类加载 → OOM 排查
系统学习运行时数据区 → 对象布局 → 对象创建 → 逃逸分析 → GC 判定 → GC 算法 → 收集器 → 类加载 → OOM
查漏补缺直接找对应知识点定向阅读

记住:JVM 不是"调优工具箱",而是一套系统性的运行时环境。理解它的设计原理,才能在遇到问题时快速定位、在性能调优时做出正确决策。