G1停顿预测模型基于衰减平均与衰减标准差进行保守估算,公式为MAX2(davg + σ×dsd, davg×confidence_factor),通过加权历史数据、动态置信补偿和波动缓冲,精准预测各Region回收耗时以构建CSet。

G1 的停顿预测不是靠猜,而是用一套带“记忆权重”的数学方法实时估算每个 Region 回收要花多久。核心就是指数加权平均(也叫衰减平均),它让最近的 GC 数据说话更响,老数据慢慢淡出,贴合真实运行节奏。
为什么不用简单平均?
简单平均会把 5 分钟前一次平稳的 Young GC 和 2 秒前一次因大对象暴增导致的长停顿同等对待,结果预测值迟钝、滞后。而交易系统里,对象分配速率可能毫秒级突变——G1 必须对最新压力快速响应。指数加权平均通过一个固定衰减因子(默认 α = 0.7)实现这一点:每次新耗时进来,旧均值只保留 70%,新值占 30%。这样,连续几次异常 GC 就能明显拉高预测值,模型“反应快”了。
公式背后的关键逻辑
实际代码中,预测值不是直接取衰减均值,而是:
预测耗时 = MAX2( davg + σ × dsd , davg × confidence_factor )
其中:
- davg 是衰减均值,代表“最近几次的典型耗时”
- dsd 是衰减标准差,衡量耗时波动程度;σ 默认为 0.5,意味着模型主动预留半倍标准差的缓冲
- confidence_factor 是置信度系数:样本少于 5 次时,它大于 1(比如刚启动时是 2.5),防止模型过早自信;样本够了就归 1
这个设计本质是“保守估计”:宁可多留点时间,也不能低估。尤其在 Mixed GC 中扫描 Remembered Set 或复制存活对象时,波动大,靠标准差项兜底。
它怎么用在选 Region 上?
G1 不是算“总共要多少毫秒”,而是算“回收第 N 个 Region 预计多花多久”。每个 Region 的子阶段(扫描、转移、RSet 更新)都维护独立的 TruncatedSeq 序列,各自跑衰减平均。构建 CSet 时,G1 按「收益 / 预估耗时」排序 Region,然后从高到低累加预估值——一旦接近 -XX:MaxGCPauseMillis 设定值,立刻停止。所以预测不准,不是模型坏了,而是输入变了:比如某次 Survivor 区对象年龄集体跳升,复制开销骤增,但模型还没积累够新样本,davg 还卡在旧水平,结果实际超时。
怎么看它是不是在正常工作?
开 -Xlog:gc+ergo=debug,关注每条 Evacuation Pause 日志末尾:
[debug][gc,ergo] GC(42) predicted pause time: 142.3ms, target: 150.0ms, actual: 138.7ms
重点比对 predicted 和 actual 的差值趋势:
- 连续几次 predicted → 模型低估,常见于 Humongous 分配激增或跨代引用突增
- 连续几次 predicted > actual 且差值 >30ms → 模型太保守,可能是上次发生 Concurrent Mode Failure 后调高了安全系数
- predicted 在 80–180ms 来回跳 → 老年代 Region 存活率不稳定,缓存没设上限或批量任务集中晋升










