CMS并行GC收集器是大多數(shù)JAVA服務(wù)應(yīng)用的最佳選擇,然而隔盛, CMS并不是完美的,在使用CMS的過程中會產(chǎn)生2個最讓人頭痛的問題:
promotion failed
該問題是在進(jìn)行Minor GC時拾稳,Survivor Space放不下吮炕,對象只能放入老年代,而此時老年代也放不下造成的访得。(promotion failed時老年代CMS還沒有機(jī)會進(jìn)行回收龙亲,又放不下轉(zhuǎn)移到老年代的對象,因此會出現(xiàn)下一個問題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
該問題是在執(zhí)行CMS GC的過程中同時業(yè)務(wù)線程將對象放入老年代,而此時老年代空間不足搜骡,或者在做Minor GC的時候拂盯,新生代Survivor空間放不下,需要放入老年代记靡,而老年代也放不下而產(chǎn)生的谈竿。
下面是一個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]
下面我們詳細(xì)的分析這兩個問題產(chǎn)生的原因以及如何進(jìn)行解決。
首先我們經(jīng)常遇到promotion failed問題摸吠,這也確實(shí)是個很頭痛的問題榕订,一般是進(jìn)行Minor GC的時候,發(fā)現(xiàn)Survivor空間不夠蜕便,所以劫恒,需要移動一些新生帶的對象到老年帶,然而轿腺,有些時候盡管老年代有足夠的空間两嘴,但是由于CMS采用標(biāo)記清除算法,默認(rèn)并不使用標(biāo)記整理算法族壳,可能會產(chǎn)生很多碎片憔辫,因此,這些碎片無法完成大對象向老年帶轉(zhuǎn)移仿荆,因此需要進(jìn)行CMS在老年帶的Full GC來合并碎片贰您。
這個問題的直接影響就是它會導(dǎo)致提前進(jìn)行CMS Full GC, 盡管這個時候CMS的老年代并沒有填滿坏平,只不過有過多的碎片而已,但是Full GC導(dǎo)致的stop-the-wold是難以接受的锦亦。
解決這個問題的辦法就是可以讓CMS在進(jìn)行一定次數(shù)的Full GC(標(biāo)記清除)的時候進(jìn)行一次標(biāo)記整理算法舶替,CMS提供了以下參數(shù)來控制:
-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5
也就是CMS在進(jìn)行5次Full GC(標(biāo)記清除)之后進(jìn)行一次標(biāo)記整理算法,從而可以控制老年代的碎片在一定的數(shù)量以內(nèi)杠园,甚至可以配置CMS在每次Full GC的時候都進(jìn)行內(nèi)存的整理顾瞪。
另外,有些應(yīng)用存在比較大的對象朝生熄滅抛蚁,這些對象在救助空間無法容納陈醒,因此,會提早進(jìn)入老年代瞧甩,老年代如果有碎片钉跷,也會產(chǎn)生promotion failed, 因此我們應(yīng)該控制這樣的對象在新生代,然后在下次Minor GC的時候就被回收掉肚逸,這樣避免了過早的進(jìn)行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收集器進(jìn)行回收,我們在線上尤其要注意的是concurrent mode failure出現(xiàn)的頻率苍鲜,這可以通過-XX:+PrintGCDetails來觀察思灰,當(dāng)出現(xiàn)concurrent mode failure的現(xiàn)象時,就意味著此時JVM將繼續(xù)采用Stop-The-World的方式來進(jìn)行Full GC混滔,這種情況下洒疚,CMS就沒什么意義了,造成concurrent mode failure的原因是當(dāng)minor GC進(jìn)行時坯屿,1)舊生代所剩下的空間小于Eden區(qū)域+From區(qū)域的空間油湖,或者2)在CMS執(zhí)行老年代的回收時有業(yè)務(wù)線程試圖將大的對象放入老年代,導(dǎo)致CMS在老年代的回收慢于業(yè)務(wù)對象對老年代內(nèi)存的分配领跛。
解決這個問題的通用方法是調(diào)低觸發(fā)CMS GC執(zhí)行的閥值乏德,CMS GC觸發(fā)主要由CMSInitiatingOccupancyFraction值決定,默認(rèn)情況是當(dāng)舊生代已用空間為68%時吠昭,即觸發(fā)CMS GC喊括,在出現(xiàn)concurrent mode failure的情況下,可考慮調(diào)小這個值矢棚,提前CMS GC的觸發(fā)郑什,以保證舊生代有足夠的空間。
總結(jié):
- promotion failed – concurrent mode failure
Minor GC后蒲肋, Survivor空間容納不了剩余對象蘑拯,將要放入老年代钝满,老年代有碎片或者不能容納這些對象,就產(chǎn)生了concurrent mode failure, 然后進(jìn)行stop-the-world的Serial Old收集器申窘。
解決辦法:-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5 或者調(diào)大新生代或者Survivor空間
- concurrent mode failure
CMS是和業(yè)務(wù)線程并發(fā)運(yùn)行的弯蚜,在執(zhí)行CMS的過程中有業(yè)務(wù)對象需要在老年代直接分配,例如大對象偶洋,但是老年代沒有足夠的空間來分配熟吏,所以導(dǎo)致concurrent mode failure, 然后需要進(jìn)行stop-the-world的Serial Old收集器。
解決辦法:+XX:CMSInitiatingOccupancyFraction玄窝,調(diào)大老年帶的空間牵寺,+XX:CMSMaxAbortablePrecleanTime
總結(jié)一句話:使用標(biāo)記整理清除碎片和提早進(jìn)行CMS操作。
【轉(zhuǎn)自】https://my.oschina.net/hosee/blog/674181