CMS收集器中两个致命的问题

175 阅读2分钟

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 failureCMS特有的错误,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区过小,导致晋升速率过快
  • 存在大对象