深入解析java虚拟机:垃圾回收,最大并发标记清除垃圾回收器

图10-8 CMS GC

垃圾回收策略有很多名称,如Young GC、Full GC、Minor GC、Major GC和Mixed GC等,实际上对于HotSpot VM来说,只有Partial GC和Full GC。Partial GC表示只清理堆的部分区域。Minor GC与Young GC等价,都表示只清理新生代,Old GC表示只清理老年代,Mixed GC表示清理整个新生代和部分老年代,它们都属于Partial GC。Full GC表示清理整个堆,通常它等价于Major GC。本文主要是用Young GC(以下简称YGC)和Full GC(以下简称FGC)两种表示。

CMS GC除了有负责清理新生代的YGC、特殊情况下的FGC外,还有只回收老年代的垃圾回收策略,即Old GC。Old GC大部分过程允许Mutator线程和GC线程一起进行,此时Mutator线程无须停止,这种方式称为并发垃圾回收,所使用的算法称为并发标记清除算法。

对象丢失问题

======

传统的标记清除算法分为标记、清除两个阶段。为了将它改造为并发算法,CMS GC将标记清除算法细分为初始标记、并发标记、预清理、可中断预清理、重新标记、并发清理,重置几个阶段,其中只有初始标记和重新标记需要STW,其他最耗时的阶段允许GC线程和Mutator线程一起进行。正是因为它有两个阶段需要STW,所以CMS GC的名字是最大程度(Mostly)的并发而非完全(Completely)并发。Mutator线程和GC线程一起工作会造成一些问题,如图10-9所示。

深入解析java虚拟机:垃圾回收,最大并发标记清除垃圾回收器

图10-9 并发标记问题

三色抽象(Tricolor Abstraction)可以简洁地描述回收过程中对象状态的变化,所以本节将使用三色抽象描述对象标记过程:图10-9中黑色表示对象及成员都被处理,浅色网格表示对象本身已处理,白色表示未处理对象。

起初垃圾回收器已经处理了A、B、C对象,并正在处理E对象成员。由于Mutator线程可以与GC线程一起工作,所以Mutator线程可以更新B对象的引用,使其指向D对象,并删除G对象对D对象的引用。由于B对象已经被标记为黑色对象,不会再做扫描,所以GC只会继续处理E对象,并清扫未被标记的D对象。更进一步,研究表明,只要同时满足以下两条要求就会造成存活对象丢失:

Mutator线程插入了从黑色对象指向白色对象的新引用;

Mutator线程删除了从灰色对象指向该白色对象的所有可能路径。

“垃圾回收器只能清理垃圾”是垃圾回收器最重要的原则,如果只是简单地引入并发算法,则会违背该原则,因此,并发垃圾回收器必须处理对象丢失问题。

常用的解决对象丢失的方法有增量更新(Incremental Update)和SATB(Snapshot At The Beginning,起始快照)技术。

增量更新的原理是打破第一个条件,通过写屏障记录下Mutator线程对黑色对象的增量修改,然后重新扫描这些黑色对象,以图10-9为例,当删除G到D的引用,并添加B到D的引用时,增量更新的写屏障会记录对象G并将它标记为灰色以等待二次处理。

SATB的原理是打破第二个条件,同样的例子,SATB写屏障会将D放入标记栈等待后续处理。

CMS GC使用增量更新技术,具体实现方式是复用其他分代GC处理跨代引用的卡表和写屏障代码,只要黑色对象写入白色对象的引用,就记录在卡表中以等待后续重新标记阶段再次扫描。这样做的问题是由于卡表本来用于处理跨代引用,每次YGC后都会重置,导致CMS GC需要的数据可能被重置掉,因此CMS GC引入了mod-union表,当CMS GC的Old GC进行并发标记时,每发生一次YGC,就会在重置卡表前更新mod-union表的对应数据。

Old GC周期

========

CMS GC在Old GC中实现了并发标记清除算法,在创建CMSCollector时,虚拟机会同时创建ConcurrentMarkSweepThread(以下简称CMS GC线程),用于负责Old GC的实际工作,如代码清单10-16所示:

代码清单**10-16

ConcurrentMarkSweepThread::run_service**

void ConcurrentMarkSweepThread::run_service() {

while (!should_terminate()) {

sleepBeforeNextCycle(); // 阻塞一段时间,直到下一次Old GC发生

if (should_terminate()) break; // 如果请求退出则终止CMS GC线程

GCIdMark gc_id_mark;

GCCause::Cause cause = _collector->_full_gc_requested ?

_collector->_full_gc_cause : GCCause::_cms_concurrent_mark;

_collector->collect_in_background(cause); // 清理老年代

}

}

CMS GC线程会进入一个循环,每次它调用sleepBeforeNextCycle()时会阻塞一段时间,唤醒后使用

CMSCollector::collect_in_background()清理老年代,如代码清单10-17所示:

代码清单10-17 collect_in_background

void CMSCollector::collect_in_background(GCCause::Cause cause) {

switch (_collectorState) {

// 初始标记(STW)

case InitialMarking:{ReleaseForegroundGC x(this);

stats().record_cms_begin();

VM_CMS_Initial_Mark initial_mark_op(this);

VMThread::execute(&initial_mark_op);

}

break;

// 并发标记

case Marking: markFromRoots();break;

// 预清理

case Precleaning: preclean();break;

// 可中断预清理

case AbortablePreclean: abortable_preclean();break;

// 重新标记(STW)

case FinalMarking:{

ReleaseForegroundGC x(this);

VM_CMS_Final_Remark final_remark_op(this);

VMThread::execute(&final_remark_op);

}

break;

// 并发清理

case Sweeping: sweep(); // fallthrough

case Resizing: {

ReleaseForegroundGC x(this);

MutexLockerEx y(…);

CMSTokenSync z(true);

if (_collectorState == Resizing) {

compute_new_size();save_heap_summary();

_collectorState = Resetting;

}

break;

}

// 重置垃圾回收器的各种数据结构

case Resetting: … break;

case Idling:

default: ShouldNotReachHere();break;

}

}

collect_in_background实现了一个完整的Old GC,代码使用状态机模式,通过_collectorState状态转换来切换到不同的垃圾回收周期,简化了代码逻辑。

1. 初始标记

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

最后

小编利用空余时间整理了一份《MySQL性能调优手册》,初衷也很简单,就是希望能够帮助到大家,减轻大家的负担和节省时间。

关于这个,给大家看一份学习大纲(PDF)文件,每一个分支里面会有详细的介绍。

image

这里都是以图片形式展示介绍,如要下载原文件以及更多的性能调优笔记(MySQL+Tomcat+JVM)!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

外链图片转存中…(img-AOEraQj6-1712745227022)]

这里都是以图片形式展示介绍,如要下载原文件以及更多的性能调优笔记(MySQL+Tomcat+JVM)!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-Qy1ClIa1-1712745227022)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值