调优cms触发比率需合理设置-xx:cmsinitiatingoccupancyfraction(ciof),使其在老年代“忙不过来”前启动并发回收,避免频繁gc或concurrent mode failure;默认值因jdk版本而异,jdk9+已移除cms;建议起始值65%~75%,配合-xx:+usecmsinitiatingoccupancyonly禁用自适应并观察gc日志;最终ciof应基于老年代增长斜率、cms并发标记耗时及安全余量动态计算确定。

调优 CMS 收集器的触发比率,核心是合理设置 -XX:CMSInitiatingOccupancyFraction(简称 CIOF),让它在老年代真正“忙不过来”之前就启动并发回收,既避免频繁 GC,又防止 concurrent mode failure 导致 STW 式 Full GC。
理解触发逻辑:不是“到点就收”,而是“赶在撑爆前动手”
CIOF=N 表示当老年代已用空间 ≥ N% 时,JVM 尝试启动 CMS 并发周期。注意三点:
- 它只是“尝试触发”,不保证一定执行——若 CMS 正在运行中、或内存分配太快来不及响应,就会跳过
- 默认值因 JDK 版本而异(JDK 6+ 常为 92%,JDK 7u4 后 JVM 会自适应计算,通常在 60%~90% 浮动)
- 必须搭配
-XX:+UseConcMarkSweepGC使用;JDK 9+ 已移除 CMS,不可用
设定初始值:从 65%~75% 起步,别凭空猜
经验起点不是 50% 或 90%,而是中间偏保守的区间:
- 对象晋升稳定、流量平缓的服务:可设为 70%~75%
- 突发流量多、晋升速率波动大(如秒杀、日志密集型):建议 60%~65%
- 设得太低(如 ≤50%):CMS 频繁启动,CPU 占用高,吞吐下降
- 设得太高(如 ≥85%):极易触发 concurrent mode failure,退化为 Serial Old,STW 时间可能达数秒
锁定阈值并观察日志:关掉自适应,才能看清问题
JVM 默认会根据历史 GC 行为动态调整触发点,这对调优反而是个干扰。应显式启用:
-
-XX:+UseCMSInitiatingOccupancyOnly:强制每次均按你设的 CIOF 值触发,不再自适应 - 配套开启详细 GC 日志:
-Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps - 重点看日志中每次
initial-mark时刻的老年代使用率(如[ParOldGen: 2845M->2845M(4096M)]中的 2845/4096 ≈ 69.4%) - 是否频繁出现
concurrent mode failure字样?这是最直接的失败信号
动态微调:基于增长斜率与并发耗时反推安全水位
理想 CIOF 不是固定数字,而是由三要素决定:
-
老年代增长斜率:单位时间(秒)内老年代增长 MB 数,可用
jstat -gc <pid> 1000 20</pid>连续采样后回归估算 -
CMS 并发标记平均耗时:取最近 10 次
concurrent-mark阶段耗时均值(排除 STW 干扰样本) - 安全余量:预留 5%~15% 空间应对浮动垃圾和突发晋升
公式示意:CIOF 应略小于 (1 − 安全余量) × (1 − 增长斜率 × 并发标记耗时)。例如增长斜率 2.6 MB/s、标记耗时 0.84s、余量取 10%,则上限约为 78%,实际可设 70%~75% 观察。











