什么是CMS?
CMS全称叫做Concurrent Mark Sweep(并发标记清除),是一款以获取最短回收停顿时间为目标的老年代收集器,适合基于B/S系统的服务器上,系统停顿时间更短,给用户带来较好的体验。
从名字(包含Mark Sweep)上就可以看出,CMS收集器使用“标记-清除”算法实现的,它的运作相对于其他垃圾收集器来说是比较复杂的,整个过程分四个步骤,包括:
- 初始标记 (CMS initial mark)
- 并发标记 (CMS concurrent mark)
- 重新标记 (CMS remark)
- 并发清除 (CMS concurrent sweep)
其中初始标记和重新标记需要“Stop The World”,初始标记仅仅是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC RootsTracing的过程,而并发标记阶段则是为了修正并发标记期间因为用户程序继续运作而导致的标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短,整个过程中耗时最长的并发标记和并发清除可以和用户线程一起工作,所以CMS收集器的内存回收过程是与用户线程一起并发执行的
CMS收集器调优
调优CMS收集器时最紧要的的工作是要避免并发模式失效和晋升失败,并发模式失效往往是由于CMS不能以足够快的速度清理老年代空间:新生代进行垃圾回收时候,CMS收集器计算发现老年代没有足够空间可以容纳这些晋升对象,不得不先对老年代进行来及回收,初始时老年代ko空间中对象一个接一个有序排列的,当老年代空间占用达到某个程度(默认70%)时,并发回收就开始了,一个收集器必须在老年代30%空间用尽之前,完成老年代空间的扫描及回收工作,如果并发回收再这场速度竞赛中失利,CMS就会发生并发模式失效
有以下途径可以避免发生这种失效:
- 想办法增大老年代空间,要么只移动部分的新生代对象到老年代,要么增加更多的堆空间。
- 以更高的频率运行后台回收线程。
- 使用更多的后台回收线程。
CMS收集器使用二个配置MaxGCPauseMllis=N和GCTimeRatio=N来确定使用多大的堆和多大的代空间。
1.给后台线程更多的运行机会
为了让CMS收集器赢得这场赛跑,方法一就是更早的启动并发收集器周期,显然的,CMS收集器在老年代空间占用达到60%是启动并发收集,这个老年代空间占用到70%才启动相比,前者完成垃圾收集的几率更大
2.调整CMS后台线程
每个CMS后台线程都会100%地占用机器上的一个CPU,如果发生并发模式失效,同同时又有额外的CPU周期可用,可以设置-XX:ConcGCThreads= N标志,增加后台线程数目。默认情况下ConcGCThreads的值是根据parallelGCThreads标志的值计算得到的
:ConcGCThreads = ( parallelGCThreads + 3 )/ 4
参考文献:
Java并发编程博客 - 不可错过的CMS学习笔记
CMS并发失效与晋升失败
深入理解JAVA虚拟机JVM高级特性与最佳实践(第2版)
Java性能权威指南