谈谈对 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 人为执行了命令