谈谈对CMS的认知?
CMS(concurrent mark sweep)在jdk1.5中已经开始使用了,2004年9月30日,JDK1.5发布。CMS设计的目标就是获取最低停顿时间(stop the world停顿时间),它是基于
标记-清除算法实现的。常用的场景是互联网网站(对服务响应要求较高),它是一个老年代垃圾收集器,可以和Serial收集器,Parallel New收集器配合使用。当并行模式(concurrent mode failure)失败时CMS会退化成Serial Old.
CMS收集器的工作流程(步骤)是什么样的?
主要四个阶段
- 初始标记:只标记和GC Roots能直连的对象,速度快,会发生(stop the world)
- 并发标记:和应用线程并发执行,遍历
初始标记阶段标记过的对象,标记这些对象的可达对象。 - 重新标记:由于
并发标记是和应用线程是并发执行的,所以有些标记过的对象发生了变化。这个过程比初始标记用时长,但是比并发标记阶段用时短。会发生(stop the world) - 并发清除:和应用线程一起运行。基于标记对象,直接清理对象。
CMS的缺点?
垃圾碎片问题
- 原因:由于CMS采用的是
标记-清除算法,所以不可避免会有内存碎片问题。 - 解决:使用
-XX:+CMSFullGCsBeforeCompaction=n,意思是在上次CMS并发GC执行过后,到底还要做多少Full GC才做压缩。默认是0,也就是说每次CMS GC顶不住了转入Full GC时都要压缩。
并发模式失败(concurrent mode failure)
- 原因:CMS垃圾清理线程和应用线程是并发执行的,如果在清理过程中老年代空间不足不能容纳新对象。
- 解决:使用
-XX:+UseCMSInitiatingOccupancyOnly和-XX:CMSInitiatingOccupancyFraction=60,指定CMS对内存的占用率到60%时开始GC。
重新标记阶段时间过长
- 解决:使用
-XX:+CMSScavengeBeforeRemark,在执行重新标记之前,先做一次Young GC,目的在于较少年轻代对老年代的无效引用,降低重新标记的开销。
为什么配置了CMS GC,却触发了Full GC?
- 大对象分配时,年轻代放不下,直接去老年代,结果老年代也放不下。
- 内存碎片问题(使用
标记-清除算法的缺点) CMS GC失败(concurrent mode failure导致)- jmap -histo 人为执行了命令