持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
收集步骤方法一
CMS是基于“标记--清除”算法实现的,在老年代中的整个过程分为4个步骤:
-
其中,初始标记,重新标记这两个步骤任然需要“stop the world”,其它两个步骤中用户线程是一起并发执行的
-
初始标记(CMS initial mark),初始标记只是标记一下GC ROOTS 能直接关联到的对象,速度很快
-
并发标记(CMS concurrent mark),并发标记阶段就是进行GC ROOTS Tracing 的过程,此时用户线程也是在同步执行的
-
重新标记(CMS remark),重新标记阶段则是为了修正并发标记期间因为用户程序继续运作而导致标记产生变动的那一部分对象的标记记录( 这部分对象是指从 GC Roots 不可达的对象,因为用户程序的并发运行,又可达了),这个阶段的停顿时间一般会比初始标记阶段稍长一些,但是远比并发标记的时间短。
-
并发清除(CMS concurrent sweep),收集在标记阶段被标识为不可访问的对象。The collection of a dead object adds the space for the object to a free list for later allocation. Coalescing of dead objects may occur at this point. Note that live objects are not moved.死亡对象收集为空闲列表增加了更多的空间,以便以后分配。在这一点上可能会发生死物体空间的的合并。请注意,不会移动活动对象。
-
CMS收集器的运作步骤如下图所示,在整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以和用户线程一起工作,因此从整体上看,CMS收集器线程的内存回收过程是与用户线程一起并发执行的。
CMS缺点
- CMS以牺牲CPU资源的代价来减少用户线程的停顿。当CPU个数少于4的时候,有可能对吞吐量影响非常大;
- CMS收集器无法处理浮动垃圾(Floating Garbage),即第一次标记,认为某个对象不是垃圾,但是在CMS线程和用户线程在并发执行的过程中此对象可能变成了垃圾,那么CMS无法在这次的垃圾回收中将它回收掉。无法处理这些垃圾可能出现”concurrent mode failure“失败而导致另一次Full GC的产生。如果在应用中老年代的增长速度不是太快,可以适当调高
-XX:CMSInitiatingOccupancyFractio的值来提高触发的百分比(不是很懂),以便降低内存回收的次数从而获取更好的性能。要是CMS运行期预留的内存无法满足程序的需要时,虚拟机将启动后备预案,临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样一来停顿的时间就更久了。所以说参数-XX:CMSInitiatingOccupancyFraction设置太高容易导致大量的”concurrent mode failure“失败,性能反而降低 - 由于基于MS算法即
Mark-Sweep,收集结束时会带来碎片问题,空间碎片过多会给大对象分配带来很大麻烦,望往往出现老年代还有很大的空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前进行一次Full GC。CMS收集器提供了一个参数:-XX:+UseCMSCompactAtFullConnection开关参数,默认是开启的,用于在CMS收集器顶不住要进行 Full GC时同时开启内存碎片的合并整理过程,内存整理的过程是无法并发的并且需要stw,空间碎片问题没有了,但停顿时间不得不变长。