1、前文回顾
CMS采用了4个阶段来垃圾回收:初始标记(STW)、并发标记、重新标记(STW)、并发清理
2、并发回收垃圾导致CPU资源紧张
并发标记和并发清理两个最耗时的阶段,垃圾回收线程和系统工作线程同时工作,会导致有限的CPU资源被垃圾回收线程占用了一部分。
并发标记:对GC Roots进行深度追踪,但老年代的存活对象比较多,导致会追踪大量对象,耗时较高
并发清理:垃圾对象从各种随机的内存位置清理掉,也是比较耗时的
CMS默认启动的垃圾回收线程的数量是(CPU核数 + 3)/ 4
3、Concurrent Mode Failure问题
CMS只不过是回收之前标记好的垃圾对象,但在清理的过程中存在新加入老年代的垃圾对象(大对象或晋升过来的对象),这种垃圾对象是‘浮动垃圾’,需要下次FullGC来清理。
-XX:CMSInitiatingOccupancyFaction 参数可以用来设置老年代占用多少比例的时候触发CMS垃圾回收
CMS垃圾回收期间,系统程序要放入老年代的对象大于了可用内存空间,此时会如何?会发生Concurrent Mode Failure,此时就会自动用“Serial Old”垃圾回收器替代CMS,强行把系统程序STW,重新进行长时间的GC Roots追踪,然后一次性把垃圾对象都回收掉,完事儿了再恢复系统线程
4、内存碎片问题
CMS采用“标记-清理”算法,会产生内存碎片问题。内存碎片会导致更加频繁的FullGC,CMS垃圾收集器 -XX:+UseCMSCompactAtFullCollection 参数默认是打开的,意思是:FullGC后,STW 然后进行碎片整理。
-XX:CMSFullGCsBeforeCompaction,意思是执行多少次Full GC之后再执行一次内存碎片整理的工作。默认值是0 (每次FullGC都进行内存整理)