CMS存在的問題
概述
CMS 是老年代垃圾回收算法,通過標記-清除的方式,=意在通過并發(fā)的方式適度減少吞吐量,減少用戶線程停頓時間。
CMS收集器對處理器資源非常敏感
CMS的在垃圾清除是使用并發(fā)清除的,如果處理器核數(shù)不高的情況下,垃圾回收會造成很高的負載。
并發(fā)回收造成的內(nèi)存不足
造成原因
在CMS的并發(fā)標記和并發(fā)清理階段,用戶線程是還在繼續(xù)運行的,程序在運行自然就還會伴隨有新的垃圾對象不斷產(chǎn)生,而這部分的垃圾對象是出現(xiàn)在標記過程結(jié)束以后,CMS無法在當次收集中處理掉它們,只好留在下次垃圾收集時再清理掉。這樣的垃圾就叫做浮動垃圾。由于垃圾收集和用戶線程是并發(fā)執(zhí)行的,因此CMS收集器不能像其他收集器那樣幾乎填滿了再進行收集,需要預留一些空間用來保存用戶新創(chuàng)建的對象。
如何處理
在JDK1.5之前老年帶使用了68%空間后就會激活CMS收集。
如果實際應用中可以適當調(diào)整參數(shù)-XX:CMSInitiatingOccu-pancyFraction 的值來提高CMS的觸發(fā)百分比,降低內(nèi)存回收頻率獲得更好的性能。
到了JDK6 CMS收集器的啟動閥值就已經(jīng)默認提升到92%。
存在問題
如果預留空間不夠怎么辦?
首先要確定這是個小概率事件,其次JVM對著的情況處理如下:
- CMS垃圾回收報錯(Concurrent Model Failure) 并發(fā)失敗。
- 啟動后備預案:凍結(jié)用戶線程的執(zhí)行,臨時啟用Serial Old收集器來重新進行老年代的垃圾收集。(這樣的話時間就會變得很長)
內(nèi)存碎片問題
由于CMS老年代使用標記-清除回收策略,因此會有內(nèi)存碎片問題。當碎片過多時,將會給大對象分配帶來麻煩,往往會出現(xiàn)老年代還有很多空間但就已經(jīng)不能保存對象了。不得不提前觸發(fā)一次Full GC。為了解決這個問題,CMS收集器提供了-XX:UseCMSCompactAtFullCollection開關(guān)參數(shù),用于在CMS收集器不得不進行Full GC時開啟內(nèi)存碎片的合并整理過程。 有參數(shù)可以配置有多少次Full GC會堆內(nèi)存碎片進行整理(-XX:CMSFullGCsBeforeCompaction)
參考:深入理解java虛擬機 - 第三版