1.核心思想
CMS垃圾回收器的关注点是系统的停顿时间,而ParallelGC关注的点是系统的系统的吞吐量。
2.CMS执行流程
CMS回收器的执行流程是:初识标记、并发标记、预清理、重新标记、并发清理、并发重置。其中初始标记和重新标记是需要独占资源的,而预清理、并发标记、并发清理和重置是可以和用户进程一起执行的。
3.CMS预清理
CMS清理中有一个预清理的操作,因为预清理之后重新标记是独占cpu的,所以一般在预清理(使用-XX:-CMSPrecleaningEnabled关闭)之前会刻意等待一次YGC发生,根据历史的数据预测下一次YGC发生的时间,在当前时间和预测时间中间时刻,进行重新标记,这样主要是为了避免新生代GC和重新标记重合,尽可能减少一次停顿的时间。
4.CMS的默认启动线程
CMS的默认启动线程是((ParallelGCThreads+3)/4),如果使用新生代ParNew,那么ParallelGCThreads也就是新生代的GC线程数量,如果有1-4个ParallelGCThreads有1一个并发线程,5-8个则有两个并发线程。
5.动态回收
因为CMS回收器不是独占式回收器,回收的同时用户线程仍然会进行运行,所以清理不了在清理过程中的垃圾,这个时候产生的垃圾又称为浮动垃圾。所以CMS回收器不会等到内存满了之后才会回收,而是在堆的使用比例达到一定程度时开始回收,这个回收阙值可以通过-XX:CMSInitiating-OccupancyFaction这个参数来设置,(在jdk8以前默认是68,jdk8则是看这个参数是否设置,如果没有则是通过下面这个公式计算出来92%。)
((100 -MinHeapFreeRatio) +(double)(CMSTriggerRatio* MinHeapFreeRatio) / 100.0)/ 100.0
// MinHeapFreeRatio默认值为40,CMSTriggerRatio默认值为80;
6.回收失败
如果应用程序内存增长过快,在CMS过程中已经出现了内存不足的情况,那么就会出现CMS回收失败,虚拟机将启动老年代串行垃圾收集器进行回收,这样应用程序将完全中断,程序停顿时间将增长。
7.垃圾碎片
因为CMS垃圾回收器是一个基于标记清除算法的垃圾回收器,在清理后后产生大量的内存碎片,这个现象会导致虽然有很多空间,但可能因为分配不了连续空间而导致进行垃圾回收,以换取一块连续内存,所以CMS提供了几个参数来解决这个问题:-XX:UseCMSCompactAtFullCollection 开关可以让CMS回收器在回收完成后进行一次内存碎片整理,而-XX“CMSFullGCsBeforeCompaction参数用于设定多少次CMS后进行一次内存压缩。
8.有关Class回收
使用CMS回收器时,如果需要回收Perm区,默认状态下,还会进行一次Full GC用于回收Perm区,如果需要CMS回收器回收Perm区则需要配置-XX:+CMSClassUnloadingEnabled,如果条件允许,那么系统在进行垃圾回收时会使用CMS垃圾回收Perm区的class数据。
9.什么时候发生Full GC(CMS 老年代回收)?
一、旧生代空间不足:java.lang.outOfMemoryError:java heap space;
二、Perm空间满:java.lang.outOfMemoryError:PermGen space;
三、CMS GC时出现promotion failed 和concurrent mode failure(Concurrent mode failure发生的原因一般是CMS正在进行,但是由于old区内存不足,需要尽快回收old区里面的死的java对象,这个时候foreground gc需要被触发,停止所有的java线程,同时终止CMS,直接进行MSC。);
四、统计得到的minor GC晋升到旧生代的平均大小大于旧生代的剩余空间;
五、主动触发Full GC(执行jmap -histo:live [pid])来避免碎片问题;