当CMS检测到老年代变量增速超过历史均值,是否会提前启动GC?
- 内容介绍
- 文章标签
- 相关推荐
本文共计814个文字,预计阅读时间需要4分钟。
CMS的悲观策略并非主动配置的开/关,而是在未启用-XX:UseCMSInitiatingOccupancyOnly时默认启用的动态预测机制。它不依赖于固定的阈值,而是根据老年代对象增长的历年趋势预测,预判即将发生空间不足,从而提前触发CMS GC,避免进入concurrent mode failure或promotion failed等高停顿场景。
悲观策略怎么判断“增长过快”
JVM 持续统计以下数据:
- 每次 CMS GC 后老年代剩余空间大小
- 两次 CMS GC 之间老年代占用增长的绝对值和速率(单位时间增长 MB)
- 最近若干次 Minor GC 晋升到老年代的平均对象大小
- 当前老年代已用空间、剩余空间及晋升压力估算
当监测到:老年代当前增长速率显著高于历史均值,且按此速率推算,剩余空间将在短时间内(例如几秒内)耗尽——JVM 就会“悲观地”认为来不及等达到 CMSInitiatingOccupancyFraction 阈值,于是立即启动 background collector。
为什么叫“悲观”而不是“智能预测”
该策略偏向保守,容易误触发:
- 一次突发流量导致短时晋升激增,可能被误判为持续性增长
- 应用存在周期性批量任务(如定时报表生成),老年代陡升后又快速回落,但 JVM 仍按线性外推
- 日志中常表现为:OldGen 使用率仅 60%–75%,却频繁发生 CMS GC,间隔接近默认的 2 秒(
CMSWaitDuration)
如何确认当前是否受悲观策略影响
关键看 JVM 参数和 GC 日志特征:
- 未设置
-XX:+UseCMSInitiatingOccupancyOnly(即使用默认动态策略) - GC 日志中 CMS GC 触发时,OldGen 使用率明显低于
-XX:CMSInitiatingOccupancyFraction=80(比如只用了 62%) - 连续多次 CMS GC 后,OldGen 占用率大幅下降(如从 62% → 25%),说明回收及时,但触发过早
- 监控图显示 CMS GC 频次与业务请求波峰弱相关,反而呈现稳定节奏(如每 2 秒一次),这是后台线程轮询 + 悲观判定的典型表现
应对思路:控节奏,稳预期
悲观策略本身是 JVM 的自我保护,不能关闭,但可降低其干扰:
- 显式添加
-XX:+UseCMSInitiatingOccupancyOnly,让 CMS 只认阈值,排除动态预测干扰,便于定位和调优 - 结合业务压测,合理下调
-XX:CMSInitiatingOccupancyFraction(如设为 70–75),给 CMS 留出更充裕的并发执行窗口 - 检查是否因 Survivor 区过小或
MaxTenuringThreshold过低,导致对象过早晋升——这会人为放大老年代增长速率,加剧悲观判定 - 若确实存在短时大晋升(如缓存预热),可临时加大老年代容量,或改用 G1(JDK 9+ 推荐)以更好适应动态负载
本文共计814个文字,预计阅读时间需要4分钟。
CMS的悲观策略并非主动配置的开/关,而是在未启用-XX:UseCMSInitiatingOccupancyOnly时默认启用的动态预测机制。它不依赖于固定的阈值,而是根据老年代对象增长的历年趋势预测,预判即将发生空间不足,从而提前触发CMS GC,避免进入concurrent mode failure或promotion failed等高停顿场景。
悲观策略怎么判断“增长过快”
JVM 持续统计以下数据:
- 每次 CMS GC 后老年代剩余空间大小
- 两次 CMS GC 之间老年代占用增长的绝对值和速率(单位时间增长 MB)
- 最近若干次 Minor GC 晋升到老年代的平均对象大小
- 当前老年代已用空间、剩余空间及晋升压力估算
当监测到:老年代当前增长速率显著高于历史均值,且按此速率推算,剩余空间将在短时间内(例如几秒内)耗尽——JVM 就会“悲观地”认为来不及等达到 CMSInitiatingOccupancyFraction 阈值,于是立即启动 background collector。
为什么叫“悲观”而不是“智能预测”
该策略偏向保守,容易误触发:
- 一次突发流量导致短时晋升激增,可能被误判为持续性增长
- 应用存在周期性批量任务(如定时报表生成),老年代陡升后又快速回落,但 JVM 仍按线性外推
- 日志中常表现为:OldGen 使用率仅 60%–75%,却频繁发生 CMS GC,间隔接近默认的 2 秒(
CMSWaitDuration)
如何确认当前是否受悲观策略影响
关键看 JVM 参数和 GC 日志特征:
- 未设置
-XX:+UseCMSInitiatingOccupancyOnly(即使用默认动态策略) - GC 日志中 CMS GC 触发时,OldGen 使用率明显低于
-XX:CMSInitiatingOccupancyFraction=80(比如只用了 62%) - 连续多次 CMS GC 后,OldGen 占用率大幅下降(如从 62% → 25%),说明回收及时,但触发过早
- 监控图显示 CMS GC 频次与业务请求波峰弱相关,反而呈现稳定节奏(如每 2 秒一次),这是后台线程轮询 + 悲观判定的典型表现
应对思路:控节奏,稳预期
悲观策略本身是 JVM 的自我保护,不能关闭,但可降低其干扰:
- 显式添加
-XX:+UseCMSInitiatingOccupancyOnly,让 CMS 只认阈值,排除动态预测干扰,便于定位和调优 - 结合业务压测,合理下调
-XX:CMSInitiatingOccupancyFraction(如设为 70–75),给 CMS 留出更充裕的并发执行窗口 - 检查是否因 Survivor 区过小或
MaxTenuringThreshold过低,导致对象过早晋升——这会人为放大老年代增长速率,加剧悲观判定 - 若确实存在短时大晋升(如缓存预热),可临时加大老年代容量,或改用 G1(JDK 9+ 推荐)以更好适应动态负载

