85-实例透彻分析CMS垃圾收集器执行过程

实例透彻分析CMS垃圾收集器执行过程

CMS收集器收集步骤:

  • Phase 1:Initial Mark 初始标记
  • Phase 2:Concurrent Mark 并发标记
  • Phase 3:Concurrent Preclean 并发预清除
  • Phase 4:Concurrent Abortable Preclean 并发中止预清除
  • Phase 5:Final Remark 最终的重新标记
  • Phase 6:Concurrent Sweep 并发清除
  • Phase 7:Concurrent Reset 并发重置
  • Phase 1:Initial Mark

    • 这个是CMS两次stop-the-world事件的其中一次,这个阶段的目标是:标记那些直接被GC Roots引用或者被年轻代存活对象所引用的所有对象。
  • 在这里插入图片描述

  • Phase 2:Concurrent Mark

    • 在这个阶段Garbage Collector 会遍历老年代,然后标记所有存活的对象,它会根据上一个阶段找到的GC Roots遍历查找。并发标记阶段,它会与用户的应用程序并发运行。并不是老年代所有的存活对象都会被标记,因为在标记期间用户的程序可能会改变一些引用。

在这里插入图片描述

  • 在上图中,与阶段1的图进行对比,就会发现有一个对象的引用已经发生了变化。
  • Phase 3:Concurrent Preclean
    • 这也是一个并发阶段,与应用的线程并发运行,并不会stop引用的线程。在并发运行的过程中,一些对象的引用可能会发生变化,但是这种情况发生时,JVM会将这个对象的区域(Card)标记为Dirty,这也就是Card Marking
    • 在pre-clean阶段,那些能够从Dirty对象到达的对象也会被标记,这个标记做完之后,dirty card标记就会被清除了。

在这里插入图片描述

  • Phase 4:Concurrent Abortable Preclean
    • 这也是一个并发阶段,但是同样不会影响用户的应用线程,这个阶段是为了尽量承担STW(Stop-the-world)中最终标记的工作。这个阶段持续时间依赖于很多的因素,由于这个阶段是在重复做很多相同的工作,直接满足一些条件(比如:重复迭代的次数,完成的工作量或者时钟时间等)
  • Phase 5:Final Remark 最终的重新标记
    • 这是第二个STW阶段,也是CMS中的最后一个,这个阶段的目标是标记老年代所有的存活对象,由于之前的阶段是并发执行的,gc线程可能跟不上应用程序的变化,为了完成标记老年代所有存活对象的目标,STW就非常有必要了。
    • 通常CMS的Final Remark阶段会在年轻代尽可能干净的时候运行,目的是为了减少连续STW发生的可能性(年轻代存活对象过多的话,也会导致老年代涉及的存活对象会很多)。这个阶段会比前面的几个阶段更复杂一些。
  • 标记阶段完成
    • 经历过这五个阶段之后,老年代所有存活的对象都被标记过了,现在可以通过清除算法去清理那些老年代不再使用的对象。
  • Phase 6:Concurrent Sweep 并发清除
    • 这里不需要STW,它是与用户的应用程序并发运行,这个阶段是:清除那些不再使用的对象,回收它们的占用空间为将来使用。

在这里插入图片描述

  • Phase 7:Concurrent Reset 并发重置
    • 这个阶段也是并发执行的,它会重设CMS内部的数据结构,为下次GC做准备
  • 总结

    • CMS通过将大量工作分散到并发处理阶段来减少STW时间,在这块做得非常优秀,但是CMS也有一些其他的问题。
    • 缺点
      • CMS收集器无法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode Failure”失败而导致Full GC的产生,可能引发串行Full GC。
      • 空间碎片,导致无法分配大对象。CMS收集器提供了一个 -XX:+UseCMSCompactAtFullCollection开关参数(默认就是开启的),用于在CMS收集器顶不住要进行Full GC时开启内存碎片的合并整理过程,内存整理的过程无法并发的,空间碎片问题没有了,但停顿时间不得不变长。
    • 对于堆比较大的应用,GC的时间难以预估。
  • 实例:
    /**
     -verbose:gc
     -Xms20M
     -Xmx20M
     -Xmn10M
     -XX:+PrintGCDetails
     -XX:SurvivorRatio=8
     -XX:+UseConcMarkSweepGC
     */
    public class MyTest5 {
        public static void main(String[] args) {
            int size = 1024 * 1024;
            byte[] myAlloc1 = new byte[4 * size];
            System.out.println("111111");
    
            byte[] myAlloc2 = new byte[4 * size];
            System.out.println("222222");
    
            byte[] myAlloc3 = new byte[4 * size];
            System.out.println("333333");
    
            byte[] myAlloc4 = new byte[2 * size];
            System.out.println("444444");
        }
    }
    

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值