一、核心垃圾回收算法
1. 基础算法
-
标记-清除(Mark-Sweep)
- 流程:标记存活对象 → 清除未标记对象。
- 优点:实现简单,无对象移动开销。
- 缺点:内存碎片化,分配效率低。
- 适用场景:老年代(如CMS收集器)。
-
复制算法(Copying)
- 流程:将存活对象从“From”区复制到“To”区 → 清空“From”区。
- 优点:无碎片,分配高效。
- 缺点:内存利用率仅50%。
- 适用场景:新生代(如Serial、ParNew收集器)。
-
标记-整理(Mark-Compact)
- 流程:标记存活对象 → 向内存一端移动 → 清理边界外空间。
- 优点:无碎片,内存利用率高。
- 缺点:移动对象成本高,STW时间长。
- 适用场景:老年代(如Parallel Old、G1收集器)。
2. 分代收集算法(Generational Collection)
- 核心思想:按对象生命周期划分内存区域(新生代、老年代)。
- 新生代:存活率低,使用复制算法。
- 老年代:存活率高,使用标记-清除或标记-整理算法。
- 优化机制:大对象直接进入老年代,避免频繁复制。
二、垃圾收集器详解
1. 经典收集器
-
Serial收集器
- 算法:新生代(复制算法)、老年代(标记-整理)。
- 特点:单线程,STW时间长,适合客户端/小内存场景。
- 优点:简单高效,无线程交互开销。
- 缺点:多核利用率低,停顿时间不可控。
-
Parallel Scavenge/Old收集器
- 算法:新生代(复制算法)、老年代(标记-整理)。
- 特点:多线程并行回收,以吞吐量为优化目标。
- 优点:高吞吐(CPU用于业务代码时间占比高)。
- 缺点:全GC时间长,不适合低延迟场景。
-
CMS(Concurrent Mark-Sweep)收集器
- 算法:标记-清除。
- 流程:初始标记(STW)→ 并发标记 → 重新标记(STW)→ 并发清除。
- 特点:低延迟,减少STW时间。
- 优点:响应速度快,适合Web应用。
- 缺点:内存碎片化,CPU资源竞争激烈。
2. 现代收集器
-
G1(Garbage-First)收集器
- 算法:混合标记-整理与复制算法,堆划分为多个Region。
- 流程:初始标记 → 并发标记 → 最终标记 → 筛选回收。
- 特点:可预测停顿时间,兼顾吞吐与延迟。
- 优点:适合大内存(数十GB),区域化回收。
- 缺点:内存占用较高,小内存场景效率低。
-
ZGC收集器
- 算法:并发标记-整理,基于染色指针和读屏障。
- 特点:STW时间控制在10ms内,支持TB级堆内存。
- 优点:极致低延迟,无碎片问题。
- 缺点:JDK11+实验性功能,硬件要求高。
-
Shenandoah收集器
- 算法:并发标记-整理,通过Brooks指针实现。
- 特点:与ZGC类似,开源社区驱动。
- 优点:低延迟,兼容性强。
- 缺点:成熟度低于ZGC。
三、三色标记法与并发问题
1. 三色标记原理
- 颜色定义:
- 白色:未扫描对象(潜在垃圾)。
- 灰色:已扫描但子引用未完成。
- 黑色:完全扫描的存活对象。
- 流程:
- 初始标记(STW):标记GC Roots直接引用对象为灰色。
- 并发标记:遍历灰色对象,递归标记子对象。
- 最终标记(STW):修正并发阶段的引用变化。
2. 并发标记问题
-
漏标(存活对象被误删)
- 条件:
- 黑色对象新增对白色对象的引用。
- 灰色对象删除对白色对象的引用。
- 解决方案:
- 增量更新(CMS):记录新增引用,重新标记黑色对象为灰色。
- 原始快照(SATB,G1):记录删除前的引用关系,按快照重新扫描。
- 条件:
-
多标(浮动垃圾)
- 原因:已标记对象在并发阶段失去引用。
- 影响:产生浮动垃圾,下次GC回收,不影响程序正确性。
四、选择与调优建议
1. 收集器选择
场景 | 推荐收集器 | 理由 |
---|---|---|
低延迟(实时系统) | ZGC/Shenandoah | 停顿时间可控(<10ms) |
高吞吐(批处理) | Parallel Scavenge | 最大化CPU用于业务代码 |
中小内存(客户端) | Serial/CMS | 简单高效,资源占用低 |
大内存(数十GB以上) | G1/ZGC | 区域化回收,平衡吞吐与延迟 |
2. 调优方向
- 减少STW时间:
- 增大堆内存(降低GC频率)。
- 使用低延迟收集器(如G1/ZGC)。
- 降低内存碎片:
- 老年代优先选择标记-整理算法。
- 避免频繁分配大对象。
- 监控工具:
- 通过GC日志分析工具(如GCViewer)定位瓶颈。
- 使用JVM参数(如
-Xmx
、-XX:+UseG1GC
)优化配置。
五、总结
Java垃圾回收机制通过算法创新(如三色标记法)和分代设计,平衡了内存利用率、吞吐量和延迟。现代收集器(如G1、ZGC)进一步通过并发、区域化和硬件优化,支持更大内存和更低延迟场景。实际应用中需结合业务需求(吞吐、延迟、内存大小)选择合适的收集器,并通过监控调优提升系统性能。