JVM 垃圾回收(GC)
一、第一性原理层(Why)
1. 为什么需要垃圾回收
根本问题:
程序如何判断一块内存是否还“有价值”?
在现代高级语言中:
- 对象的**使用权**由程序逻辑决定
- 对象的**生命周期**却难以由程序员精确管理
如果完全依赖人工释放:
- 易产生悬挂指针、重复释放
- 难以应对异常、并发、复杂控制流
结论:
垃圾回收的本质,是把“内存生命周期管理”从业务逻辑中剥离,交由运行时系统统一治理。
2. GC 的本质定义
无论实现如何变化,所有 GC 都在解决同一个问题:
在不破坏程序语义的前提下,找出仍然可能被使用的对象,其余内存可以被安全重用。
抽象为两个不可分割的子问题:
- **存活对象发现(Live Object Discovery)**
- **内存空间重用(Space Reclamation & Reuse)**
二、理论模型层(What)
3. 对象“是否存活”的理论判定
3.1 引用计数模型(被否定的方案)
思想:
- 每个对象维护一个引用计数
被否定的根本原因:
- 无法处理**循环引用**
- 在真实语言语义中需要大量额外修正
JVM 放弃该方案,并非性能问题,而是正确性难以保证。
3.2 可达性分析模型(GC 的理论基石)
核心思想:
对象是否存活,不取决于“被引用次数”,而取决于是否仍可被程序访问。
模型定义:
- 从一组 **GC Roots** 出发
- 沿着引用关系遍历对象图
- 能到达的对象 = 存活对象
这是 JVM GC 的第一性理论基础。
4. GC Roots 的哲学含义
GC Roots 不是随意选择,而是满足一个原则:
只要程序还能“直接使用”的对象,就必须作为根。
因此包括:
- 线程栈中的局部变量
- 类静态变量
- 常量池引用
- JNI、本地代码引用
5. 引用强度模型(对象生存策略)
引用不是二元的(有 / 无),而是一个策略梯度:
| 引用类型 | 本质定位 | 设计目的 |
|---|---|---|
| 强引用 | 必须存活 | 程序正确性 |
| 软引用 | 可牺牲 | 内存弹性(缓存) |
| 弱引用 | 不阻止回收 | 生命周期绑定 |
| 虚引用 | 仅做通知 | 资源回收协调 |
引用模型的本质,是让程序参与“内存价值排序”。
三、分代与对象行为假说(Why + What)
6. 分代收集的理论前提
JVM 并非随意分代,而是基于三条经验假说:
- **弱分代假说**:绝大多数对象朝生夕灭
- **强分代假说**:活得越久的对象越难死亡
- **跨代引用假说**:跨代引用远少于同代引用
GC 分代不是优化技巧,而是对象行为统计学。
7. 分代的抽象角色划分
| 代 | 本质角色 | 回收目标 |
|---|---|---|
| 新生代 | 高死亡率区 | 快速回收 |
| 老年代 | 高稳定区 | 减少频率 |
分代的真正目的:
用不同策略处理不同“生存概率”的对象。
四、核心回收算法(How)
8. 三大基础算法的哲学权衡
8.1 标记-清除(Mark-Sweep)
- 优点:实现简单
- 根本缺陷:**内存碎片**
适用场景:
- 对象稳定
- 回收频率低
8.2 标记-复制(Mark-Copy)
- 优点:无碎片、分配快
- 代价:牺牲空间
本质适配:
高死亡率区域(新生代)
8.3 标记-整理(Mark-Compact)
- 优点:空间连续
- 代价:对象移动成本
哲学权衡:
停顿时间 vs 吞吐量
五、并发 GC 的不变量与工程约束
9. 为什么并发 GC 如此困难
根本冲突:
GC 在“看对象图”,而程序在“改对象图”。
10. 三色标记不变量
| 颜色 | 含义 |
|---|---|
| 白 | 未访问(可能垃圾) |
| 灰 | 已访问,未扫描完 |
| 黑 | 已完全扫描 |
并发正确性的核心不变量:
黑对象不能直接引用白对象
11. 两大并发修正思想
| 思想 | 代表 | 本质 |
|---|---|---|
| 增量更新 | CMS | 关注“新增引用” |
| 原始快照(SATB) | G1 / ZGC | 固定起始视图 |
六、HotSpot 架构支撑机制(How)
12. Safepoint / Safe Region
GC 不是随时可做的,而必须在引用关系稳定点执行。
Safepoint 的本质:
- 在**可验证一致性**的时间点暂停世界
13. OopMap
OopMap 解决的问题不是“快”,而是:
如何在暂停时准确知道哪里是引用。
14. 记忆集与卡表
设计目标:
避免全堆扫描老年代。
卡表是:
- 空间换时间
- 精度换性能
七、垃圾收集器 = 策略组合体
15. 衡量 GC 的三大指标
| 指标 | 含义 |
|---|---|
| 吞吐量 | 程序执行效率 |
| 延迟 | 停顿时间 |
| 内存占用 | 运行成本 |
GC 设计是典型的不可能三角问题。
16. 典型收集器的设计定位
| 收集器 | 核心追求 | 代价 |
|---|---|---|
| Serial | 极简 | 长停顿 |
| Parallel | 吞吐 | 延迟不可控 |
| CMS | 低延迟 | 碎片 |
| G1 | 可预测 | 实现复杂 |
| ZGC | 极低延迟 | 架构复杂 |
八、现代 GC 的演进趋势
17. 演进主线
对象规模 ↑ → 堆容量 ↑ → 人类容忍停顿 ↓
因此:
- 从 STW → 并发
- 从 分代 → Region
- 从 写屏障 → 读屏障
关联内容(自动生成)
- [/编程语言/JAVA/JVM/自动内存管理/内存结构.html](/编程语言/JAVA/JVM/自动内存管理/内存结构.html) JVM内存结构与垃圾回收机制密切相关,不同的内存区域采用不同的回收策略,理解内存结构是掌握垃圾回收的基础
- [/编程语言/JAVA/JVM/自动内存管理/调优.html](/编程语言/JAVA/JVM/自动内存管理/调优.html) 垃圾回收参数调优是JVM性能优化的重要组成部分,了解各种GC算法的特点有助于制定合适的调优策略
- [/编程语言/JAVA/JVM/JAVA内存模型.html](/编程语言/JAVA/JVM/JAVA内存模型.html) Java内存模型与垃圾回收机制共同构成了JVM内存管理的完整体系,理解两者关系有助于深入掌握内存管理机制
- [/编程语言/JAVA/JVM/JVM.html](/编程语言/JAVA/JVM/JVM.html) JVM整体架构和运行机制的理解有助于更好地掌握垃圾回收在其中的作用和意义
- [/编程语言/JAVA/JVM/类加载机制.html](/编程语言/JAVA/JVM/类加载机制.html) 类加载过程与垃圾回收相互影响,类的生命周期管理是内存管理的重要方面