JVM - 老年代垃圾收集器CMS产生的问题分析

Concurrent Mark Sweep 垃圾收集器,GC 过程中不可避免的问题:

1、 promotion failed

2、concurrent mode failure

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]


问题产生的原因:

promotion failed 是新生代进行 Minor GC时, Survivor Space 放不下,对象只能放入老年代,而此时老年代也放不下造成的。多数是由于老年代有足够的空闲空空间但碎片多。此时必然触发 concurrent mode failure。

concurrent mode failure 是在执行 CMS GC 的过程中业务线程将对象放入老年代,而此时老年代空间不足,CMS 还没来得及进行回收; 或者 Minor GC过程中,救助空间放不下,老年代也放不下。

解决方案参考:

1. CMS 基于标记-清除算法,默认不使用标记整理算法,GC 过程会产生很多碎片针对这个问题,可以让 CMS 在进行一定次数的 Full GC(标记清除)的时候进行一次标记整理算法,

配置:

-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5


2. 有些应用存在比较大的对象朝生夕死,这些对象在救助空间无法容纳而提早进入老年代。我们可以增大救助空间的大小,控制这样大对象保持在新生代,在下一次 Minor 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
 

3. 调整触发 CMS GC 执行的阀值,CMS GC 触发主要由 CMSInitiationOccupancyFraction 值决定,默认情况是当老年代已用空间为68%时,自动触发 CMS GC , 如果频繁出现 concurrent mode failure ,可以考虑调小这个阀值,提前触发 CMS GC, 以保证老年代有足够的空间。

总结:提前触发 CMS GC、适当使用标记整理碎片和增大救助空间大小。

发布了187 篇原创文章 · 获赞 26 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/huangdingsheng/article/details/102826311
今日推荐