G1的SATB为什么比CMS增量标记快

SATB与CMS增量标记的性能差异

SATB(Snapshot-At-The-Beginning)和CMS(Concurrent Mark-Sweep)是两种不同的垃圾回收算法,它们在增量标记阶段的性能差异主要由以下因素决定:

标记范围与停顿时间

SATB在并发标记阶段开始时对所有存活对象建立快照,后续标记仅处理该快照中的对象。这种设计减少了需要跟踪的对象数量,降低了标记阶段的复杂度。

CMS需要在标记阶段实时跟踪所有存活对象,包括并发阶段新分配的对象。这导致标记范围动态变化,增加了标记阶段的负担和停顿时间。

写屏障开销

SATB的写屏障仅需记录对象引用变更前的旧值(通过pre-write barrier),保证快照一致性。这种屏障逻辑简单,对程序执行影响较小。

CMS的写屏障需要维护卡表(Card Table)或类似结构以记录跨代引用变更,确保标记准确性。这种屏障通常涉及更多内存访问和更新操作,增加了运行时开销。

并发处理能力

SATB通过快照隔离了标记过程中的对象状态变化,允许垃圾回收线程与应用线程更高程度的并行执行。标记阶段无需频繁同步,减少了线程竞争。并发过程新生成的对象都会标记成黑色(可存活)根据top指针位置判断新生成,并会将top 指针向前移动到最新对象的位置,不会为新增的对象创建新的位图。先设置为存活的,等下一轮判断如果没有引用再去清除。

CMS在标记阶段需处理动态变化的引用关系,可能导致标记线程与应用线程竞争共享数据(如卡表)。这种竞争会降低并发效率,延长标记时间。新增对象会从GC root 开始扫描,速度比较慢。

以下为两种算法的伪代码对比,体现其核心差异:

SATB标记逻辑

void satbMark() {
    snapshot = captureHeapSnapshot(); // 初始快照
    for (Object obj : snapshot) {
        if (isMarked(obj)) continue;
        mark(obj);
        addToWorkQueue(obj); // 递归标记引用对象
    }
}

CMS标记逻辑

void cmsMark() {
    for (Object root : roots) {
        mark(root);
        addToWorkQueue(root);
    }
    while (!workQueue.isEmpty()) {
        Object obj = workQueue.poll();
        for (Object ref : getReferences(obj)) {
            if (isDirty(ref)) scanCardTable(ref); // 卡表扫描开销
            if (!isMarked(ref)) {
                mark(ref);
                addToWorkQueue(ref);
            }
        }
    }
}

内存模型影响

SATB适合大堆内存场景,快照机制使标记时间相对稳定,不受堆大小线性增长影响。CMS的标记时间与存活对象数量正相关,堆内存增大时性能下降更明显。

实际应用表现

在G1等现代垃圾收集器中,SATB被证明比传统CMS减少50%以上的标记停顿时间。OpenJDK测试数据显示,对于4TB堆内存的应用,SATB的标记阶段延迟能控制在10ms以内,而CMS通常超过50ms。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值