CMS 垃圾回收器

什么是 CMS

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的老年代收集器。目前很大一部分的 Java 应用集中在互联网站或者 B/S 系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS 收集器就非常符合这类应用的需求。

运行过程

从名字(Mark Sweep)上就可以看出,CMS 收集器是基于标记—清除算法实现的,它的运作过程相对于前面几种收集器来说更复杂一些,整个过程分为 4 个步骤,如下:

  1. 初始标记,时间较短,仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快。
  2. 并发标记,和用户的应用程序同时进行,进行 GC Roots 追踪的过程,标记从 GC Roots 开始关联的所有对象开始遍历整个可达分析路径的对象。这个时间比较长,所以采用并发处理(垃圾回收器线程和用户线程同时工作)。
  3. 重新标记,时间较短,为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
  4. 并发清除,用户和应用程序同时进行,清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。

由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,从总体上来说,CMS 收集器的内存回收过程是与用户线程一起并发执行的。

image-20210823140236159

概念性的东西往往难以记住,我们换个方式来理解,假如你去饭店吃饭:

  1. 当服务员刚上菜的时候,是两只大龙虾,服务员告诉你为了不影响其他顾客用餐不要把龙虾壳乱扔(这个大龙虾我们把他当做比较明显的GC Roots对象),这个时候你的状态是在听取意见(暂停)而并没有开始进餐,也就是对应的初始标记
  2. 服务员说完之后你开始进餐,你在吃龙虾的过程中,把龙虾壳放在了你正前面的盘子里面,这个时候服务员对你说如果盘子里的龙虾壳(垃圾)满了他就来清理,此时你吃你的,他说他的,互不干扰,是一个同时进行的过程,这个过程可以理解为并发标记
  3. 当你面前的盘子满了之后,你把盘子从你的正前面放到了另外的一个位置,并且你叫服务员来清理一下,然后准备等清理之后在继续吃第二只龙虾(也就是说你现在处于暂停的状态),但此时服务员手上都是垃圾,于是他又重新记住了盘子的位置说等下就来,这个过程可以理解为重新标记
  4. 此时,服务员重新给了你一个新的盘子,然后你就继续吃下一只龙虾,服务员就把装满龙虾壳的盘子给收走了,你吃你的,他收他的,这个过程可以理解为并发清除

也就是说,你吃东西的过程当做用户线程,而服务员收垃圾的过程当做GC,感觉是挺好理解的。

存在的问题

CMS 的优秀主要就是体现在它的并发和低停顿,但同时它也存在一些缺点,主要表现在这 4 个方面:

  1. CPU 敏感:CMS 对处理器资源敏感,因为采用了并发的收集、当处理核心数不足 4 个时,CMS 对用户的影响较大。

  2. 浮动垃圾:由于 CMS 并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS 无法在当次收集中处理掉它们,只好留待下一次 GC 时再清理掉。这一部分垃圾就称为浮动垃圾。

  3. 并发模式失败:由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。在 1.6 的版本中老年代空间使用率阈值(92%) 如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure,这时虚拟机将临时启用 Serial Old 来替代 CMS。

    简单来说就是在老年代内存要满的时候会进行Full GC,但在Full GC的过程中可能会有新的对象进入老年代,那此时必定会进入 STW 的状态,并且 CMS 会自动切换到用Serial old垃圾收集器来回收。Serial是一个单线程的垃圾回收器。那这种情况出现是不是会严重降低我们的执行效率?

  4. 内存碎片:CMS采用的是标记 - 清除算法,因此会导致产生不连续的内存碎片。

总体来说,CMS 是 JVM 推出了第一款并发垃圾收集器,所以还是非常有代表性。但是最大的问题是 CMS 采用了标记清除算法,所以会有内存碎片,当碎片较多时,给大对象的分配带来很大的麻烦,为了解决这个问题,CMS 提供一个参数:-XX:+UseCMSCompactAtFullCollection,一般是开启的,如果分配不了大对象,就进行内存碎片的整理过程。

那为什么 CMS 采用标记-清除?

在实现并发的垃圾回收时,如果采用标记整理算法,那么还涉及到对象的移动(对象的移动必定涉及到引用的变化,这个需要暂停业务线程来处理栈信息,这样使得并发收集的暂停时间更长,而 CMS 的主要目的就是为了降低 STW 的时间),所以使用简单的标记-清除算法才可以降低 CMS 的 STW 的时间。该垃圾回收器适合回收堆空间几个G~ 20G 左右。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪了个王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值