聊聊cms GC中的concurrent mode failure

在上一篇,耗时20多秒的young gc,你见过吗? 的结尾,给大家预告了一个有趣的case,现在开始分享一下。

 

直接上图↓

图1

从红框1中,可以看到cms full gc开始进行初始化标记了,紧接着在红框二处,开始了并发标记,说到这里,再贴个好图,帮大家回忆一下cms的几个阶段↓

图2

言归正传,图1红框3中,可以看到,有7次由于新生代空间不足,导致allocation failure引起的young gc,然后再图1红框4中,可以看到,此时jvm堆空间也已经使用了3760040K,也就是3.6G,而整个堆只有4G。

 

敲黑板,重点来了,当young gc的时候,把eden和survivor里的都还存活的对象,统一移到另一个survivor区中时,发现装不下了,就需要把部分对象,放到老年代中去,结果老年代空间也不足,这种场景呢,叫做promotion failed

 

在promotion failed的前提下,老年代恰好还正在full gc,那么就会有图1红框5中的字样提示,concurrent mode failure。

 

在图一红框6中,可以看到整个堆的使用空间从4032680K(3.8G),变成了868795K(0.8G),这是一次真实耗时3.77秒,会有STW现象的full gc ,也叫做备份gc。

 

有的同学可能会疑惑,这个full gc有点慢呀, 是的。其中一个很大的原因,就是concurrent mode failure情况下的full gc使用的并不是cms的垃圾回收器,而是使用的Serail-Old垃圾回收器,全程是单线程串行操作, 肯定比较慢。

 

为啥concurrent mode failure了,就要退化成Serail-Old呢 ?来看看R大的回答↓

 

可是,不是有一个ParallelOld回收器吗?直接用呗,为啥非要用serial-old呢?原因是这个回收器与CMS GC不兼容所以无法作为它的备份full GC使用。

 

说完了原因,再来看看解决方案,从两方面着手,首先是排查应用程序的内存泄漏问题,看看是否有频繁且大量的不必要的创建对象的操作,再就是评估下当前的系统负载和容量情况,看是否需要扩容调整。

 

如果程序代码排查没问题、容量也没问题,那就要进行jvm参数的调优了,加上-XX:UseCMSCompactAtFullCollection参数来减少内存碎片,本文中的情况是新生代较小(只有300M),因此还有很多对象晋升到老年代,于是老年代内存使用量也涨的比较快,所以可以适当通过-XX:NewSize和-XX:MaxNewSize来调整下新生代的大小。

 

如果新生代大小是合理的话,则可以调大老年代的容量,如果内存有限的话,可以适当调小XX:CMSInitiatingOccupancyFraction参数,让老年代提前进行GC,预留足够的空间来接纳新生代的晋升对象。

 

实战中,需要结合真实情况,对症下药~

 

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值