CMS介绍
CMS全称Concurrent Mark Sweep,从名字可知是基于“标记——清除”算法实现。以获取最短回收停顿时间为目标;
总的来说,由上图可知CMS垃圾回收有四个步骤:
- 初始标记(Initial Mark)
标记GC Roots能直接关联到的对象,速度很快。 - 并发标记(concurrent mark)
遍历初始标记阶段标记出来的存活对象,然后继续递归标记这些对象可达的对象 - 重新标记(remark)
修正由于并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录 - 并发清理(concurrent sweep)
与用户线程一起运行,清理那些无效的对象。
其中初始标记和重新标记需要Stop The World,但时间很短。并发标记与并发清理需要时间较长,但是可以和用户线程并发执行。
CMS缺点:
- 无法处理浮动垃圾而导致concurrent mode failure
浮动垃圾:由于CMS并发清理阶段,用户线程的运行会导致新的垃圾产生,但是这一部分垃圾出现在标记阶段之后,CMS无法在当次收集中处理,只能在下次GC中清理,这一部分垃圾就称为“浮动垃圾”。
所以说CMS需要在老年代预留部分空间供并发收集时的程序运作使用。那么问题来了,CMS什么时候开始工作呢?也就是说CMS在老年代在使用百分之多少的空间时激活呢。太小不行,使用内存空间会小,这样垃圾容易满,GC次数会变多。
在JDK1.6中,阈值为92%(通过-XX:CMSInitiatingOccupancyFraction=)设置,预留的8%空间如果无法满足程序需要,就会出现concurrent mode failure。
这时JVM就会启用Serial Old收集器重新进行单线程STOP The World垃圾收集。效率极具下降。
- 基于“标记——清除”算法会产生内存碎片,进而导致promotion failure
这是一个剩余空间不够的问题,剩余空间不够不是说整体的空间不够分配某个对象,而是说连续的空间不够分配给某个对象。所以一旦内存碎片大多就可能发生剩余空间不够的问题。(-XX:UseCMSCompactAtFullCollection和-XX:CMSFullGCBeforeCompaction=0 配合使用可以设置每次进行Full GC都开启碎片整理,不过这两个默认就是开启的,实际不需要设置)
promotion failure:minor gc过程中,另一个survivor的剩余空间不足以容纳eden及当前在用survivor区间存活对象,只能将容纳不下的对象移到年老代(promotion),而此时年老代由于剩余空间不够,无法容纳更多对象,通常伴随full gc,因而导致的promotion failure