【Java-JVM】一次完整的 GC 流程是怎样的?
·

一次完整的 GC 流程解析(以 CMS 收集器为例)
1. 触发条件
当 老年代空间不足(或达到预设阈值)时触发 Full GC。例如:
- 大对象直接进入老年代但空间不足
- 新生代对象晋升到老年代时空间不足
- 方法区(元空间)内存不足
- 手动调用
System.gc()
2. 核心流程(分阶段)
用 打扫房间 比喻 GC 流程:
- 房间 = JVM 堆内存
- 垃圾 = 无引用的对象
- 清洁工 = GC 线程
阶段 1:初始标记(Initial Mark - STW)
- 动作:暂停所有工作(STW),快速标记 直接与 GC Roots 关联的对象(如静态变量、活动线程栈中的对象)。
- 耗时:极短(毫秒级)。
- 比喻:清洁工先锁定房间门口,快速标记门口显眼的垃圾袋(GC Roots 直接关联的对象)。
阶段 2:并发标记(Concurrent Mark)
- 动作:恢复用户线程,并发遍历对象引用链,标记所有存活对象。
- 耗时:较长(与堆大小成正比)。
- 风险:用户线程可能修改对象引用(产生"浮动垃圾")。
- 比喻:清洁工边打扫边允许住户进出房间,住户可能丢弃新垃圾(浮动垃圾)。
阶段 3:重新标记(Remark - STW)
- 动作:再次暂停所有工作,修正并发标记期间的引用变化(通过增量更新/原始快照算法)。
- 耗时:短于并发标记。
- 比喻:二次锁定房间,检查住户新丢弃的垃圾并更新标记。
阶段 4:并发清除(Concurrent Sweep)
- 动作:恢复用户线程,删除未被标记的对象,回收内存。
- 耗时:较长。
- 问题:产生内存碎片(类似房间角落残留碎屑)。
- 比喻:边允许住户活动边清扫已标记的垃圾,但房间可能不整洁(碎片)。
3. 特殊情况处理
- 内存碎片过多 → 触发 内存压缩(Mark-Compact):
移动存活对象到内存一端,消除碎片(类似重新排列家具)。 - 并发模式失败(Concurrent Mode Failure):
当 GC 速度跟不上对象分配速度时,退化为 Serial Old 收集器(全程 STW,暂停时间更长)。
4. 总结与面试要点
| 关键点 | 说明 |
|---|---|
| STW 发生阶段 | 初始标记、重新标记(尽量缩短暂停时间) |
| 并发阶段 | 并发标记、并发清除(减少对应用影响) |
| 浮动垃圾 | 并发阶段新产生的垃圾,需下次 GC 回收 |
| 适用场景 | 重视响应速度的系统(如 Web 服务) |
| 缺点 | 内存碎片、CPU 资源争用 |
| 替代方案 | G1/ZGC 收集器(解决碎片问题,可控停顿) |
✅ 核心思想:CMS 通过 部分 STW + 并发操作 平衡吞吐量和延迟,适合需要低延迟的应用。
更多推荐



所有评论(0)