CMS之promotion failed&concurrent mode failure
原文链接:https://www.jianshu.com/p/ca1b0d4107c5
CMS并行GC收集器是大多数JAVA服务应用的最佳选择,然而, CMS并不是完美的,在使用CMS的过程中会产生2个最让人头痛的问题:
promotion failed
该问题是在进行Minor GC时,Survivor Space放不下,对象只能放入老年代,而此时老年代也放不下造成的。(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的过程中同时业务线程将对象放入老年代,而此时老年代空间不足,或者在做Minor GC的时候,新生代Survivor空间放不下,需要放入老年代,而老年代也放不下而产生的。
下面是一个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]
下面我们详细的分析这两个问题产生的原因以及如何进行解决。
首先我们经常遇到promotion failed问题,这也确实是个很头痛的问题,一般是进行Minor GC的时候,发现Survivor空间不够,所以,需要移动一些新生带的对象到老年带,然而,有些时候尽管老年代有足够的空间,但是由于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操作,下面的一个配置样例就通过增加Survivor空间的大小来解决这个问题:
-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进行时,1)旧生代所剩下的空间小于Eden区域+From区域的空间,或者2)在CMS执行老年代的回收时有业务线程试图将大的对象放入老年代,导致CMS在老年代的回收慢于业务对象对老年代内存的分配。
解决这个问题的通用方法是调低触发CMS GC执行的阀值,CMS GC触发主要由CMSInitiatingOccupancyFraction值决定,默认情况是当旧生代已用空间为68%时,即触发CMS GC,在出现concurrent mode failure的情况下,可考虑调小这个值,提前CMS GC的触发,以保证旧生代有足够的空间。
总结:
- promotion failed – concurrent mode failure
Minor GC后, Survivor空间容纳不了剩余对象,将要放入老年代,老年代有碎片或者不能容纳这些对象,就产生了concurrent mode failure, 然后进行stop-the-world的Serial Old收集器。
解决办法:-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5 或者调大新生代或者Survivor空间
- concurrent mode failure
CMS是和业务线程并发运行的,在执行CMS的过程中有业务对象需要在老年代直接分配,例如大对象,但是老年代没有足够的空间来分配,所以导致concurrent mode failure, 然后需要进行stop-the-world的Serial Old收集器。
解决办法:+XX:CMSInitiatingOccupancyFraction,调大老年带的空间,+XX:CMSMaxAbortablePrecleanTime
总结一句话:使用标记整理清除碎片和提早进行CMS操作。
CMS之promotion failed&concurrent mode failure的更多相关文章
- [转]使用CMS垃圾收集器产生的问题和解决方案
在之前的一篇文章<CMS vs. Parallel GC>里通过实验的方式对比了并行和并发GC的优缺点,在文章结尾提到,CMS并行GC是大多数应用的最佳选择,然而, CMS并不是完美的,在 ...
- 垃圾收集器之:CMS收集器
HotSpot JVM的并发标记清理收集器(CMS收集器)的主要目标就是:低应用停顿时间.该目标对于大多数交互式应用很重要,比如web应用.在我们看一下有关JVM的参数之前,让我们简要回顾CMS收集器 ...
- 【JVM】CMS垃圾回收器
一.简介 Concurrent Mark Sweep,是一种以获取最短回收停顿时间为目标的收集器,尤其重视服务的响应速度. CMS是老年代垃圾回收器,基于标记-清除算法实现.新生代默认使用ParNew ...
- [面试] Java GC (未整理完)
Java GC简介 什么是 GC ? Java程序不用像C++程序在程序中自行处理内存的回收释放.这是因为Java在JVM虚拟机上增加了垃圾回收(GC)机制,用以在合适的时间触发垃圾回收. 你都了解哪 ...
- 阿里Java面经大全(整合版)
本文里的面经内容全部来源于牛客网,作为秋招备战复习与查缺补漏时使用.里面部分面经有我的注释和想法,以及部分解答,不一定正确,大家可以查询补充. 阿里巴巴,三面,java实习 昨天晚上11点打电话来,问 ...
- Java垃圾回收之回收算法
问题:谈谈你了解的垃圾回收算法 1.标记-清除算法(Mark and Sweep) 标记:从跟集合进行扫描,对存活的对象进行标记 清除:对堆内存从头到尾进行线性遍历,回收不可达对象内存 优点:简单 缺 ...
- JVM 调优 —— GC 长时间停顿问题及解决方法
零. 简介 垃圾收集器长时间停顿,表现在 Web 页面上可能是页面响应码 500 之类的服务器错误问题,如果是个支付过程可能会导致支付失败,将造成公司的直接经济损失,程序员要尽量避免或者说减少此类情况 ...
- 深入理解JVM(二)垃圾收集器
GC三问: 哪些内存需要回收? 什么时候回收? 如何回收? 程序计数器.虚拟机栈.本地方法栈随线程而生,随线程而灭,栈帧的内存分配在类结构确定下来就已知,在方法结束或者线程结束时就会回收.所以垃圾回收 ...
- Java GC CMS 日志分析
https://blogs.oracle.com/poonam/entry/understanding_cms_gc_logs 笔者对其中某几条记录又进行了详细说明,以下是一条完整的CMS日志记录的示 ...
随机推荐
- 使用pytesseract进行图像识别
引言 对于简单验证码及一些图像的识别,我们需要使用pytesseract及相应的Tesseract引擎,它是开源的OCR引擎.帮助我们做一些简单的图像识别 当然为了更好将图片识别,对一些像素比较低的图 ...
- CF1209题解
E 每列都可以沿下滚动若干次,使得各行最大值之和最大 对每列的元素计算最大值,降序排,显然取前\(min(n,m)\)个列处理即可 比较巧妙的动规,设\(f(i,S)\)为前\(i\)列,已经确定最大 ...
- CF1203F2 Complete the Projects (hard version)(结论+背包+贪心)
题目 做法 对于加分的直接贪心 而掉分的用排序后的背包动规 假设有两个物品\((a_1,b_1)(a_2,b_2)\) 选第一个物品后无法选择第二个物品,假设开始值为\(r\):\(r>a_1, ...
- WEB甘特图(机器运行状态图)
前台框架使用BootStrap轻量级框架AdminLTE 后台框架使用的是Spring.SpringMVC 初此使用数据库SQL Server故只能用JDBC连接 请勿见怪!jsp页面重复添加元素过多 ...
- Vue编程基础
一.依赖环境搭建: 添加镜像 # 安装好node.js后,使用淘宝镜像 npm install -g cnpm --registry=https://registry.npm.taobao.org 项 ...
- webpack4-用之初体验
众所周知,webpack进入第4个大版本已经有2个月的时间了,而且webpack团队升级更新的速度也是非常的惊人 在写下如下内容的时候webpack已经出到了4.6的版本了,剑指5.0应该是指日可待了 ...
- css中的浮动与定位
传送门:https://www.cnblogs.com/junwuyao/p/7435257.html
- 时间控件My97DatePicker事件监听及用法
引入js <script src="My97DatePicker/WdatePicker.js"></script> 应用 <input type=& ...
- 使用FCKeditor编辑器上传文件时中文文件名乱码
修改:editor\filemanager\browser\default\frmupload.html 文件的编码改为UTF-8 实在不行:fckeditor/editor/filemanager/ ...
- MATLAB中 H(b > g) = 2*pi - H(b > g); 作何解
H(b > g) = 2*pi - H(b > g); %b > g 会得到一个逻辑矩阵,如b=[7,5,6] ;g=[1,2,8],那么b>g会得到[1,1,0]: b< ...