CMS存在的问题
概述
CMS 是老年代垃圾回收算法,通过标记-清除的方式,=意在通过并发的方式适度减少吞吐量,减少用户线程停顿时间。
CMS收集器对处理器资源非常敏感
CMS的在垃圾清除是使用并发清除的,如果处理器核数不高的情况下,垃圾回收会造成很高的负载。
并发回收造成的内存不足
造成原因
在CMS的并发标记和并发清理阶段,用户线程是还在继续运行的,程序在运行自然就还会伴随有新的垃圾对象不断产生,而这部分的垃圾对象是出现在标记过程结束以后,CMS无法在当次收集中处理掉它们,只好留在下次垃圾收集时再清理掉。这样的垃圾就叫做浮动垃圾。由于垃圾收集和用户线程是并发执行的,因此CMS收集器不能像其他收集器那样几乎填满了再进行收集,需要预留一些空间用来保存用户新创建的对象。
如何处理
在JDK1.5之前老年带使用了68%空间后就会激活CMS收集。
如果实际应用中可以适当调整参数-XX:CMSInitiatingOccu-pancyFraction 的值来提高CMS的触发百分比,降低内存回收频率获得更好的性能。
到了JDK6 CMS收集器的启动阀值就已经默认提升到92%。
存在问题
如果预留空间不够怎么办?
首先要确定这是个小概率事件,其次JVM对着的情况处理如下:
- CMS垃圾回收报错(Concurrent Model Failure) 并发失败。
- 启动后备预案:冻结用户线程的执行,临时启用Serial Old收集器来重新进行老年代的垃圾收集。(这样的话时间就会变得很长)
内存碎片问题
由于CMS老年代使用标记-清除回收策略,因此会有内存碎片问题。当碎片过多时,将会给大对象分配带来麻烦,往往会出现老年代还有很多空间但就已经不能保存对象了。不得不提前触发一次Full GC。为了解决这个问题,CMS收集器提供了-XX:UseCMSCompactAtFullCollection开关参数,用于在CMS收集器不得不进行Full GC时开启内存碎片的合并整理过程。 有参数可以配置有多少次Full GC会堆内存碎片进行整理(-XX:CMSFullGCsBeforeCompaction)
参考:深入理解java虚拟机 - 第三版