简述CMS垃圾回收器

CMS的全称:Concurrent Mark Sweep,即「并发标记清除」
基于标记-清除算法(会产生内存碎片)
适用范围:仅针对于老年代

引入:

使用Serial 单线程和Parallel并行垃圾回收器,在垃圾回收时,用户线程会完全stop the world
为了缩短老年代STW的时间,使用并发垃圾回收器。CMS能够在「部分场景」下让GC线程和用户线程并发执行

优点:

使用多核CPU来缩短STW的时间

缺点:

1.由于使用标记-清除算法,会产生内存碎片,分配对象时内存不足,造成并发失败触发FullGC,这时老年代并发垃圾回收器会退化到SerialOld 串行垃圾回收器使用标记-整理算法并进行整理,整理至碎片减少,才能继续工作,但这会导致垃圾回收的整体时间变长
2.空间需要预留:CMS垃圾收集器可以一边回收垃圾,一边处理用户线程,那需要在这个过程中保证有充足的内存空间供用户使用。(碎片内存又加剧了空间的问题,导致出发FullGC而使卡顿时间可能更长)

过程:

【当新生代内存不足时】:Minor GC,并不属于CMS的机制 !
当建立一个新的对象时,先放到新生代的Eden区域,
当Eden伊甸园空间不足,就触发一次Minor GC垃圾回收,同时用户线程STW,会使用可达性分析算法,沿GC root根对象的引用链标记存活对象,然后使用标记-复制算法,把存活的对象从FROM区域复制到幸存区的TO区域,并将幸存的对象寿命+1,然后清除伊甸园Eden的对象,最后交换FROM和TO区域
当幸存区的对象寿命达到阀值(最大15次),就将该对象放入老年代(晋升机制)

在这里插入图片描述
【当老年代发生了内存不足】:

  1. 初始标记:当老年代发生了内存不足,进行初始标记,用户线程STW,标记GCRoot直接关联的对象,这个阶段的速度算是很快的,因为没有「向下追溯」(只标记一层)
  2. 并发标记:用户线程并发运行,根据标记为存活的对象向下追溯遍历,找出所有存活的对象;通过写屏障将老年代中引用变化的对象标记为 Dirty Card 脏卡(提高重新标记的效率,不需要扫描整个老年代 )
  3. 重新标记:用户线程STW,由于在并发标记时,由于用户线程也在工作,对象的引用可能变化,需要重新标记,遍历GCRoot和Dirty Card
  4. 并发清理:用户线程恢复并发运行,清理未使用的对象并回收

卡表:

在逻辑上将老年代分割为若干个Card,每个Card准备一个标记索引,HotSpot中每个卡占512kb

引入1:CMS的并发标记
在CMS的【并发标记】时,用户线程和GC并发执行,可能产生新的对象、或者对象引用发生变化,
如: 新生代晋升到老年代、大对象直接分配在老年代、老年代的引用变化等
这些情况需要重新标记,为了提高重新标记的效率,在【并发标记】阶段会把这些变化对象的Card标记为脏卡,这样后续就只需要扫描这些Dirty Card对象,而不需要扫描整个老年代

引入2:G1的跨代引用
【MinorGC】时,新生代回收的跨代引用(老年代引用新生代)问题,如果老年代有对象引用着新生代代,那这些被老年代引用的对象也不能回收掉;

而老年代存对象多,不可能全部去扫描,则使用 Card Table技术来避免全表扫描老年代的对象,将老年代分成一个个Card ;

如果老年代中的对象引用了新生代的对象,则对应的卡被标记为脏卡,对应新生代RemenberedSet记忆集(本质是个HashTable)会记录老年代的脏卡的索引,避免遍历整个老年代去查找新生代的引用,提高效率;

将来在对新生代进行垃圾回收时,可以先通过RenmeneredSet知道对应的脏卡,再到老年代的脏卡区域去遍历GC Root,这样减少了GC Root遍历的时间

脏卡通过post-write barrier 写屏障来实现,在每次对象引用发生变更时,都要去更新维护脏卡,此为异步操作,会将更新脏卡的指令放到 dirty card queue 队列中

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值