专栏首页JVMGCCMS垃圾收集器
原创

CMS垃圾收集器

CMS垃圾收集器收集详细步骤

  • 初始标记(Stop the world)
  • 并发标记
  • 预清理
  • 可被终止的预清理
  • 重新标记(Stop the world)
  • 并发清除
  • 并发重置

初始标记

标记GcRoots直接可达老年对象,新生代存活对象引用的老年代对象.整个过程在JDK1.7中是单线程的在JDK1.8中是多线程的(通过CMSParallelInitialMarkEnabled参数调整)。这个过程会导致STW。

初始标记标记的对象

并发标记

初始标记阶段标记过的对象开始,标记其它存活对象,这个阶段垃圾回收线程和应用线程同时运行。由于是同时运行,应用线程还在跑,会导致对象的晋升,对象引用的变化,特殊对象直接分配到老年代。这些受到影响的老年代对象所在的Card会被标记成Dirty,用于重新标记阶段扫描,老年代对象的Card被标记为Dirty的可能原因如下面绿线所示。

并发标记过程中受到影响的对象

预清理

由于上一个阶段是并发执行的未标记的变化对象只是标记成了Dirty对象,还没有处理,预清理就是来标记这些Dirty对象。如下图:在并发标记阶段3号Card被标志为Dirty。这个阶段是为重新标记阶段做准备。

image-20201108102807805

预清理将6号标志为存活对象

image-20201108103026903

可被终止的预清理

这个阶段也是为重新标志阶段做准备,在进入重新标志阶段前,最好能进行一个Minor GC,将年轻代清理一遍, 这样可以清除大部分年轻代的对象(绝大部分年轻代对象朝生夕死),尽量缩短重新标记阶段停顿时间,CMS还提供了CMSScavengeBeforeRemark参数,可以在进入重新标记之前强制进行依次Minor gc。

重新标志(remark)

预清理可被终止的预清理都是为重新标志阶段做准备,由于重新标志阶段会发生(STW),所以要保证尽肯能的停顿时间段,不然就会影响应用程序的用户体验。这个阶段扫描的目标是:年轻代+GC Roots+Dirty老年代对象,这个阶段是多线程的(XX:+CMSParallelRemarkEnabled)。

并发清除

用户线程被激活,那些未被标志的对象会被清除。'

并发重置

CMS垃圾收集器参数回到初始状态,为下一次垃圾收集做准备。

使用CMS垃圾收集器要注意的问题

重新标记停顿时间过长

80%的时间花在重新标志阶段,如果发现重新标志阶段停顿时间过长,可尝试添加-XX:+CMSScavengeBeforeRemark,在重新标志之前做一次Minor GC,目的是减少对老年代对象的无效引用,降低重新标志的开销。

内存碎片问题

CMS是基于标记-清除算法的,CMS只会删除垃圾对象,不会对内存空间做压缩,会造成内存碎片。我们需要用-XX:CMSFullGCsBeforeCompaction=n参数来调整,含义是在上一次CMS并发执行过后,还要执行多少次Full GC才做内存压缩.

concurrent mode failure

在CMS GC过程中由于应用程序也在跑,当年轻代满了,执行了Minor GC这时候,需要将存活对象放入老年代,而此时老年代空间也不足,这时CMS还没有机会回收老年代。可以设置以下两个参数

  • -XX:CMSInitiatingOccupancyFraction=75

CMS对内存的占用率达到75%将启动GC,默认为92%,太高将导致promotion failed

  • -XX:+UseCMSInitiatingOccupancyOnly

如果没有设置UseCMSInitiatingOccupancyOnly,只设置了CMSInitiatingOccupancyFraction那么JVM只在第一次使用,后续会进行自动调整。

为什么要设置以上两个参数,在垃圾收集阶段,用户线程还在运行,所以必须要留够空间让用户线程运行。CMS前五个阶段都是标记存活对象的,除了”初始标记”和”重新标记”阶段会stop the word ,其它三个阶段都是与用户线程一起跑的,就会出现这样的情况gc线程正在标记存活对象,用户线程同时向老年代提升新的对象,清理工作还没有开始,old gen已经没有空间容纳更多对象了,这时候就会导致concurrent mode failure, 然后就会使用串行收集器回收老年代的垃圾,导致停顿的时间非常长。 CMSInitiatingOccupancyFraction参数要设置一个合理的值,设置大了,会增加concurrent mode failure发生的频率,设置的小了,又会增加CMS频率,所以要根据应用的运行情况来选取一个合理的值。如果发现这两个参数设置大了会导致full gc,设置小了会导致频繁的CMS GC,说明你的老年代空间过小,应该增加老年代空间的大小了。

promotion failed

在进行Minor GC时,Survivor space放不下,对象只能放入老年代,而此时老年代也放不下,大多数情况是老年代内存碎片太多,导致没有连续的空间存放对象。

过早的晋升和晋升失败

发生Minor GC时,如果对象过大(Survivor Space存放不下)基本上会放到老年代,这种现象被称为对象过早晋升,这将导致老年代被中短期对象增张,肯能导致严重的性能问题。如果老年代也满了,会触发Full GC,这将会导致遍历整个堆,晋升失败。

解决方案

  • 如果是因为内存碎片导致的大对象提升失败,cms需要进行空间整理压缩;
  • 如果是因为提升过快导致的,说明Survivor 空闲空间不足,那么可以尝试调大 Survivor;
  • 如果是因为老年代空间不够导致的,尝试将CMS触发的阈值调低。

CMS总结

  • CMS只收集老年代,响应速度优先。
  • 重新标记会STW,停顿时间较长,所以在这之前进行一次Minor GC,会减少很多对老年代对象的无效引用。
  • 内存碎片问题导致的Full GC,请使用-XX:CMSFullGCsBeforeCompaction=n,有规律对内存进行整理减少内存碎片。
  • JDK1.7,JDK1.8设置CMS垃圾收集器XX:+UseConcMarkSweepGC

几个重要的CMS参数

  • -XX:CMSFullGCsBeforeCompaction=n Full GC n 次后进行内存压缩整理
  • -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly 内存占用70%将触发CMS GC
  • -XX:+CMSScavengeBeforeRemark CMS GC前执行一次Minor GC
wx.jpg

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CMS垃圾收集器

    CMS全称 Concurrent Mark Sweep,是一款并发的、使用标记-清除算法的垃圾回收器,如果老年代使用CMS垃圾回收器,需要添加虚拟机参数"-XX...

    黑洞代码
  • G1和CMS垃圾收集器详解

    CMS收集器是一种以获取最短回收停顿时间为目标的收集器。很大一部分是应用在互联网网站或者浏览器的B/S系统的服务端。

    小土豆Yuki
  • 用了很多年的 CMS 垃圾收集器,终于换成了 G1,真香!!

    作者:Eric Fu 链接:https://ericfu.me/g1-garbage-collector/

    Java技术栈
  • HotSpot垃圾收集器1 Serial垃圾收集器2 ParNew垃圾收集器3 Parallel Scavenge垃圾收集器老年代垃圾收集器1 Serial Old垃圾收集器2 Parallel Ol

    JavaEdge
  • 《深入理解java虚拟机》学习笔记4——Java虚拟机垃圾收集器

    http://blog.csdn.net/chjttony/article/details/7883748#comments

    bear_fish
  • JVM之垃圾回收-垃圾收集器

    如果说前面介绍的收集算法(JVM之垃圾回收-垃圾收集算法)是内存回收的抽象策略,那么垃圾收集器就是内存回收的具体实现。

    谙忆
  • JVM(HotSpot) 垃圾收集器

    java404
  • 垃圾收集器

    HotSpot按照分代收集,所以在不同代上产生了多种不同的收集器,随着时间的推移,有些已经弃用,有些已经成为经典,还有目前广泛使用的,如图1-19所示就是7个经...

    胖虎
  • Java 垃圾收集器的垃圾收集算法

    在 Java 中,垃圾回收是个基础而有趣的话题,本文主要讲解 Java 垃圾收集器的垃圾收集算法,首先,需要理解几个概念:

    CS实验室
  • JVM垃圾收集器(GC)有哪些?

    对于jvm来说垃圾是指运行程序中没有任何指针指向的对象,这个对象就需要被回收。

    逍遥壮士
  • 深入理解JVM - CMS收集器

    上一节我们讲解分代和垃圾回收算法,这一节我们来讲解老年代重要的垃圾收集器:cms收集器。这一节的内容同样比较多。

    阿东
  • 【JVM进阶之路】七:垃圾收集器盘点

    在前面,我们已经了解了JVM的分代收集,知道JVM垃圾收集在新生代主要采用标记-复制算法,在老年代主要采用标记-清除和标记-整理算法。接下来,我们看一看JDK默...

    三分恶
  • Java虚拟机详解(四)------垃圾收集器

      上一篇博客我们介绍了Java虚拟机垃圾回收,介绍了几种常用的垃圾回收算法,包括标记-清除,标记整理,复制等,这些算法我们可以看做是内存回收的理论方法,那么在...

    IT可乐
  • JVM面试问题系列:7种JVM垃圾收集器特点,优劣势、及使用场景!

    Serial 是一款用于新生代的单线程收集器,采用复制算法进行垃圾收集。Serial 进行垃圾收集时,不仅只用一条线程执行垃圾收集工作,它在收集的同时,所有的用...

    zhisheng
  • JVM:这是一份全面 & 详细的 常见垃圾收集器 汇总攻略

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    Carson.Ho
  • 一文彻底搞懂 CMS GC 参数配置

    近期整理多个 HBase 集群的 JVM 参数,发现都是默认的 CMS GC 配置,如何调优 JVM 参数就成了一个绕不过的话题。因此,为了寻求一个 CMS G...

    大数据技术架构
  • JVM垃圾收集器详解

    一个单线程的收集器,使用复制算法。它只会使用一条线程工作,并且在进行垃圾收集的同时,必须暂停其他所有的工作线程(Stop The Word),直到垃圾收集结束。

    Java学习录
  • 深入浅出java虚拟机系列:(三)jvm常用垃圾收集器

    上面有7中收集器,分为两块,上面为新生代收集器,下面是老年代收集器。如果两个收集器之间存在连线,就说明它们可以搭配使用。

    爱笑的架构师
  • HotSpot JVM 垃圾收集器

    7种垃圾收集器作用于不同的分代,如果两个收集器之间存在连续,就说明他们可以搭配使用。

    java乐园

扫码关注云+社区

领取腾讯云代金券