CMS是一个很好的并发垃圾收集器,但是使用过程中会产生两个重要的问题。
promotion failed 晋升失败
concurrent mode failure 收集器无法处理浮动垃圾
promotion failed 晋升失败原因
> 该问题发生在Minor GC过程中,Survivor Space放不下转移的对象,老年代也放不下(promotion failed发生的时候老年代CMS还没有机会进行回收,又放不下转移到老年代的对象,下一步就会产生concurrent mode fialure,发生STW降级为Serial Old)
> 下面是一条promotion failed失败的日志
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产生的原因
> concurrent mode failure是CMS特有的错误,CMS的垃圾清理线程和用户线程是并行进行的. 老年代正在清理,从年轻代晋升了新对象,或者分配的大对象在新生代放不下,直接在老年代分配内存,这时老年代也放不下,则会抛出concurrent mode failure
concurrent mode failure的影响
> 老年代的垃圾收集器从CMS退化成Serial Old,所有用户线程被暂停,停顿时间变长。
解决方案
CMS触发太晚
>-XX:CMSInitiatingOccupancyFraction=N 是指设定CMS在对内存占用率达到N%的时候开始GC(因为CMS会有浮动垃圾,所以一般都较早启动GC);
将:-XX:CMSInitiatingOccupancyFraction=N调小
空间碎片太多
> 开启空间碎片整理,并将空间碎片整理周期设置在合理范围,-XX:CMSFullGCsBeforeCompaction作用:设置在执行多少次Full GC后对内存空间进行压缩整理。
-XX:+UseCMSCompactAtFullCollection (空间碎片整理)
-XX:CMSFullGCsBeforeCompaction=n
垃圾产生太快
晋升阈值太小
Survivor空间过小
Eden区过小,导致晋升速率过快
存在大对象