CMS vs G1 GC 写屏障:拦截时机与漏标的根本原因

文章目录

  • [一、三色标记中的漏标来源(CMS 与 G1 都要解决这个)](#一、三色标记中的漏标来源(CMS 与 G1 都要解决这个))
  • [二、CMS vs G1 写屏障:核心对比表](#二、CMS vs G1 写屏障:核心对比表)
  • 三、动画级理解
    • [情况 ①:黑对象新增指向白对象](#情况 ①:黑对象新增指向白对象)
    • [情况 ②:灰对象删除对另一个对象的引用(危险:对象消失)](#情况 ②:灰对象删除对另一个对象的引用(危险:对象消失))
  • 四、为什么拦的时机不一样但都能正确?
  • 五、总结

CMS 拦"新增引用"
G1 拦"删除引用"

为什么拦的东西不一样?为什么都能避免漏标?


一、三色标记中的漏标来源(CMS 与 G1 都要解决这个)

漏标的根本原因:

并发标记期间,应用线程改变引用结构 → 让 GC 的视图与真实情况不一致。

有两类危险变化:

场景 例子 危险
① 黑对象新增指向白对象 A(黑).ref = C(白) C 永不再被扫描 → 被误删
② 灰对象删除对白对象的引用 A(灰).ref = null B 被"从可达图消失" → 被误删

CMS 处理第一类

G1(SATB)处理第二类

下面正式进入对比。


二、CMS vs G1 写屏障:核心对比表

项目 CMS(Incremental Update) G1(SATB)
写屏障触发时机 新增引用时触发 A → B 删除引用时触发 A → B(旧引用保留)
拦截内容 新的引用指向 被删掉的旧引用
防止的漏标类型 黑对象新增指向白对象 灰对象丢失引用导致对象消失
保证的视图 标记阶段的实时可达性 GC 开始那一刻的快照可达性
原理 把新增引用的目标对象重新标记为灰色 把旧引用对象加入"快照缓冲区",继续标记
哲学 "新增引用不能漏" "起始快照不能漏"
更复杂程度 较简单 更复杂(但更强健)

三、动画级理解

我们用一个统一的例子比较:

复制代码
A → B → C

GC 扫描到一半:

复制代码
A(黑) → B(灰) → C(白)

现在应用线程做事了。


情况 ①:黑对象新增指向白对象

应用线程执行:

java 复制代码
A.ref2 = C

形成:

复制代码
A(黑) ─▶ C(白)   (危险:黑 → 白)

🔶 CMS 做法(Incremental Update 写屏障)

拦新增引用

"黑对象 A 指向了白对象 C?

C 必须重新标记为灰色!"

动画:

复制代码
A(黑) → C(灰)

这样 C 就会被标记,不会漏。


🔷 G1(SATB)怎么处理这个?

G1 不处理!直接无视!

为什么?

因为 SATB 的视角是:

"我只保证 GC 开始时 的存活快照正确。

C 在开始时本来就是白色(垃圾)。

你后面引用它不影响这次 GC 的正确性。"

结果:

  • CMS 认为 C 不应被删除,必须标记
  • G1 认为 C 本来就可回收,标不标都无所谓

🎯 这是两者哲学的核心区别!


情况 ②:灰对象删除对另一个对象的引用(危险:对象消失)

应用线程执行:

java 复制代码
B.ref = null

原本:

复制代码
B(灰) → C(白)

变成:

复制代码
B(灰)    C(白)

C 成为"孤儿",危险。


🔷 G1(SATB)做法

拦删除引用

  • 写屏障记录旧引用 B→C
  • 把 C 放进 SATB Buffer → 继续标记

动画:

复制代码
C(灰) → 最终变黑

SATB 守住的是:

"开始时 C 是可达的,我必须保证它被标记。"


🔶 CMS 会怎么做?

CMS 不处理删除引用!

CMS 的目标是避免黑→白(新增引用)

删除引用是否导致对象变成垃圾 → CMS 不关心


四、为什么拦的时机不一样但都能正确?

CMS 的世界观:

"黑对象新增引用白对象最危险,我要补标。"

CMS 的 GC 模型:

  • 保证"实时可达性"
  • 所以新增引用必须补标
  • 删除引用不会造成错误(对象从可达变不可达没关系)

G1(SATB)的世界观:

"我要保证 GC 开始那一瞬间的快照正确。"

所以:

  • 删除引用 → 可能导致当时的存活对象丢失 → 必须拦
  • 新增引用 → 不在快照里,不需要补标

🎯 G1 目标不是实时可达性,而是快照一致性。


五、总结

场景 1:黑新增指向白

复制代码
A(黑) ─▶ C(白)
  • CMS:把 C 变灰(补标)
  • G1:忽略(C 不属于起始快照,不需要处理)

场景 2:灰丢失引用白

复制代码
B(灰) → C(白)   删除引用后 → C 消失
  • CMS:不处理
  • G1:把旧 C 记录 → 变灰 → 标黑

CMS 写屏障采用 Incremental Update,拦"新增引用",修补黑→白问题。
G1 写屏障采用 SATB,拦"删除引用",保存旧引用,保护起始快照中的对象。
一个维护"实时可达性",一个维护"快照一致性"。


相关推荐
YGGP3 小时前
【Golang】LeetCode 75. 颜色分类
算法·leetcode
陈震_3 小时前
《字节外包二面凉经》
java·字节外包
北山小恐龙3 小时前
针对性模型压缩:YOLOv8n安全帽检测模型剪枝方案
人工智能·深度学习·算法·计算机视觉·剪枝
涛涛北京3 小时前
【强化学习实验】- PPO
算法
2301_797312263 小时前
学习Java29天
java·算法
苹果醋33 小时前
java设计模式之责任链模式
java·运维·spring boot·mysql·nginx
爱笑的眼睛114 小时前
深入 Django 表单 API:从数据流到高级定制
java·人工智能·python·ai
Qiuner4 小时前
Spring Boot AOP(三) 通知执行链源码解析
java·spring boot·后端
hashiqimiya4 小时前
通过前端修改后端,后端接收数组类型为string
java