使用CMS垃圾收集器产生的问题和解决方案
点击上方 好好学java ,选择 星标 公众号
重磅资讯、干货,第一时间送达
今日推荐:2020,搞个 Mac 玩玩!个人原创+1博客:点击前往,查看更多
作者:藤伦柳揶
链接:https://www.jianshu.com/p/dbd32622ad20
1.问题预览
CMS并行GC是大多数应用的最佳选择,然而, CMS并不是完美的,在使用CMS的过程中会产生2个最让人头痛的问题:
promotion failed
concurrent mode failure
第一个问题promotion failed是在进行Minor GC时,Survivor Space放不下,对象只能放入老年代,而此时老年代也放不下造成的,多数是由于老年带有足够的空闲空间,但是由于碎片较多,这时如果新生代要转移到老年带的对象比较大,所以,必须尽可能提早触发老年代的CMS回收来避免这个问题(promotion failed时老年代CMS还没有机会进行回收,又放不下转移到老年带的对象,因此会出现下一个问题concurrent mode failure,需要stop-the-wold GC- Serail Old)。
下面是一个promotion failed的一条gc日志:
106.641: [GC 106.641: [ParNew (promotion failed): 14784K->14784K(14784K), 0.0370328 secs]106.678: [CMS106.715: [CMS-concurrent-mark: 0.065/0.103 secs] [Times: user=0.17 sys=0.00, real=0.11 secs]
(concurrent mode failure): 41568K->27787K(49152K), 0.2128504 secs] 52402K->27787K(63936K), [CMS Perm : 2086K->2086K(12288K)], 0.2499776 secs] [Times: user=0.28 sys=0.00, real=0.25 secs]
第二个问题concurrent mode failure是在执行CMS GC的过程中同时业务线程将对象放入老年代,而此时老年代空间不足,这时CMS还没有机会回收老年带产生的,或者在做Minor GC的时候,新生代救助空间放不下,需要放入老年代,而老年代也放不下而产生的。
尽管CMS使用一个叫做分配担保的机制,每次Minor GC之后要保证新生代的空间survivor + eden > 老年带的空闲时间,但是对象分配是不可预测的,总会有写对象分配在老年带是满足不了的。
下面是一个concurrent mode failure的一条gc日志:
0.195: [GC 0.195: [ParNew: 2986K->2986K(8128K), 0.0000083 secs]0.195: [CMS0.212: [CMS-concurrent-preclean: 0.011/0.031 secs] [Times: user=0.03 sys=0.02, real=0.03 secs]
(concurrent mode failure): 56046K->138K(57344K), 0.0271519 secs] 59032K->138K(65472K), [CMS Perm : 2079K->2078K(12288K)], 0.0273119 secs] [Times: user=0.03 sys=0.00, real=0.03 secs]
2.原因和解决方案
首先我们经常遇到promotion failed问题,这也确实是个很头痛的问题,一般是进行Minor GC的时候,发现救助空间不够,所以,需要移动一些新生带的对象到老年带,然而,有些时候尽管老年带有足够的空间,但是由于CMS采用标记清除算法,默认并不使用标记整理算法,可能会产生很多碎片,因此,这些碎片无法完成大对象向老年带转移,因此需要进行CMS在老年带的Full GC来合并碎片。
这个问题的直接影响就是它会导致提前进行CMS Full GC, 尽管这个时候CMS的老年带并没有填满,只不过有过多的碎片而已,但是Full GC导致的stop-the-wold是难以接受的。
解决这个问题的办法就是可以让CMS在进行一定次数的Full GC(标记清除)的时候进行一次标记整理算法,CMS提供了以下参数来控制:
-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5
也就是CMS在进行5次Full GC(标记清除)之后进行一次标记整理算法,从而可以控制老年带的碎片在一定的数量以内,甚至可以配置CMS在每次Full GC的时候都进行内存的整理。
另外,有些应用存在比较大的对象朝生熄灭,这些对象在救助空间无法容纳,因此,会提早进入老年带,老年带如果有碎片,也会产生promotion failed, 因此我们应该控制这样的对象在新生代,然后在下次Minor GC的时候就被回收掉,这样避免了过早的进行CMS Full GC操作,下面的一个配置样例就通过增加救助空间的大小来解决这个问题:
-Xmx4000M -Xms4000M -Xmn600M -XXmSize=500M -XX:MaxPermSize=500M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled eCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log
上面讨论了promotion failed引起的原因以及解决方案,除了promotion failed还有一个情况会引起CMS回收失败,从而退回到Serial Old收集器进行回收,我们在线上尤其要注意的是concurrent mode failure出现的频率,这可以通过-XX:+PrintGCDetails来观察,当出现concurrent mode failure的现象时,就意味着此时JVM将继续采用Stop-The-World的方式来进行Full GC,这种情况下,CMS就没什么意义了,造成concurrent mode failure的原因是当minor GC进行时,旧生代所剩下的空间小于Eden区域+From区域的空间,或者在CMS执行老年带的回收时有业务线程试图将大的对象放入老年带,导致CMS在老年带的回收慢于业务对象对老年带内存的分配。
解决这个问题的通用方法是调低触发CMS GC执行的阀值,CMS GC触发主要由CMSInitiatingOccupancyFraction值决定,默认情况是当旧生代已用空间为68%时,即触发CMS GC,在出现concurrent mode failure的情况下,可考虑调小这个值,提前CMS GC的触发,以保证旧生代有足够的空间。
3.总结
promotion failed – concurrent mode failure
Minor GC后, 救助空间容纳不了剩余对象,将要放入老年带,老年带有碎片或者不能容纳这些对象,就产生了concurrent mode failure, 然后进行stop-the-world的Serial Old收集器。
解决办法:-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5 或者 调大新生代或者救助空间
concurrent mode failure
CMS是和业务线程并发运行的,在执行CMS的过程中有业务对象需要在老年带直接分配,例如大对象,但是老年带没有足够的空间来分配,所以导致concurrent mode failure, 然后需要进行stop-the-world的Serial Old收集器。
解决办法:+XX:CMSInitiatingOccupancyFraction,调大老年带的空间,+XX:CMSMaxAbortablePrecleanTime
★
总结一句话:使用标记整理清除碎片和提早进行CMS操作。
”
使用CMS垃圾收集器产生的问题和解决方案相关推荐
- 0 full gc时cpu idle_结合GC日志讲讲CMS垃圾收集器
1 CMS垃圾收集器介绍 CMS(Concurrent Mark Sweep)收集器旨在获取最短回收停顿时间的并发垃圾收集器.CMS基于"标记-清除"算法实现,并发指的是CMS的垃 ...
- CMS垃圾收集器详解
概述 CMS垃圾收集器是一款优秀的老年代并发垃圾收集器,通过与用户线程并发执行的方式减少GC停顿的时间.本文主要聊一下CMS设计到的相关的数据结构.具体的执行过程.运行中会出现的异常情况. 在CMS之 ...
- CMS垃圾收集器和G1垃圾收集器
CMS CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的老年代收集器.CMS收集器与之前的垃圾收集器最大的特点就是它可以并发清除垃圾. 他的工作流程如下: ...
- CMS垃圾收集器详解(转载)
文章目录 概念 CMS的GC过程 初始标记 并发标记 并发预处理 重新标记 并发清除 CMS的缺点 总结: 概念 CMS全称为Concurrent Mark Sweep,即 并发标记清除,对比其他的收 ...
- 面试官:今天还是来聊聊CMS垃圾收集器呗?
面试官:今天还是来聊聊CMS垃圾收集器呗? 候选者:嗯啊- 候选者:如果用Seria和Parallel系列的垃圾收集器:在垃圾回收的时,用户线程都会完全停止,直至垃圾回收结束! 候选者:CMS的全称: ...
- 删除已弃用的CMS垃圾收集器的JEP草案
在2017年4月10日的文章" Java垃圾收集器:G1GC何时将CMS强制退出? ",我讨论了JEP 291 ("弃用并发标记扫描(CMS)垃圾收集器"),并 ...
- 垃圾收集器总结--CMS垃圾收集器
目录 一.CMS 1.1 概述 1.2 内存碎片 1.3 浮动垃圾 1.4 空间预留 1.4 Promotion Failed和Concurrent Mode Failure 1.5 常用参数 二.总 ...
- 【深入理解JVM】CMS垃圾收集器
GC 问题处理能力能不能系统性掌握?一些影响因素都是互为因果的问题该怎么分析?比如一个服务 RT 突然上涨,有 GC 耗时增大.线程 Block 增多.慢查询增多.CPU 负载高四个表象,到底哪个是诱 ...
- 【面试高频题】CMS垃圾收集器是如何工作的?
CMS全称 Concurrent Mark Sweep,是一款并发的.使用标记-清除算法的垃圾回收器,以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器,对于要求服务器响应速度的应用上,这种垃圾回收 ...
最新文章
- HDU 2498 Digits
- [C#]使用HttpWebRequest请求远端服务器时如何加载SSL证书
- 攻防世界dice_game(pwn)
- jvm 06-G1收集器
- Shell_Shell调用SQLPlus简介(案例)
- Java 笔记(二)
- ETL学习之八:添加日志记录
- 190107每日一句
- windows 安装 perl 教程
- 《我的初恋、我的老婆》超爆笑!!
- OpenGL3D图形、旋转、纹理、键盘移动、光照、滤波、透明(完整)
- U盘中毒后,手把手教你恢复文件
- java 表格 列删除_Java 删除Excel表格中的空白行或列
- 抽丝剥茧Reactor模式
- JavaScript ES5-ES6详解
- 租车出行如何避免踩坑,区块链技术解决信任问题
- 15.全文检索-ElasticSearch
- 关于ABB软件的使用和干涉区设定
- IJPay 聚合支付系列文章
- python操作数据库教程_Python连接mysql数据库及简单增删改查操作示例代码
热门文章
- Linux platform总线(1):总体框架
- 各个级别镜像之间的跳转模型
- [ARM异常]-ARMV8的中断的routing和Mask表
- android推送如何推送不在线设备,推送系统从0到1(四):消息如何到达用户设备...
- Ubuntu下pip安装、升级、卸载
- 【安全技术】关于几种dll注入方式的学习
- python封装一个效率极高的 批量更新、插入合一的工具
- 利用SSH 反向代理 ,实现跨局域网连接家里的linux 主机 (树莓派)
- ListView 设置高度为刚好能包裹子元素
- MySQL删除用户权限(REVOKE)