G1停顿预测模型本质是衰减加权历史数据,非简单平均:用衰减均值(davg)和衰减标准差(dsd)结合置信因子动态预测本次GC可回收Region数,以逼近-XX:MaxGCPauseMillis目标。

停顿预测模型本质是加权历史数据,不是简单平均
G1 的 MaxGCPauseMillis 不是硬性上限,而是它用衰减平均(Decaying Average)从历史 GC 步骤耗时中“猜”这次能干多少事。关键不是算“平均每次花多久”,而是让最近几次的耗时数据权重更高——因为 JVM 行为随负载变化快,上周的 GC 时间对今天参考价值远低于 5 分钟前那一次。
get_new_prediction 函数怎么用衰减均值和衰减标准差做预测
这个函数在 hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp 里,核心逻辑就一行:
return MAX2(seq->davg() + sigma() * seq->dsd(), seq->davg() * confidence_factor(seq->num()));
它实际做了两件事:
-
seq->davg()是衰减均值:越近的 GC 耗时权重越大,公式里 α 默认取 0.9,意味着上次数据占 10% 权重,其余 90% 来自之前所有数据的加权结果 -
seq->dsd()是衰减标准差,衡量历史耗时波动程度;sigma()默认是 0.5(来自G1ConfidencePercent=50),所以davg() + 0.5 * dsd()相当于“均值 + 半个波动范围”,是个偏保守的预估上限 - 当历史样本少于 5 次时,
confidence_factor()会大于 1(比如只有 2 次就拉到 2.0),强制放大预测值,避免因数据太少而低估耗时、导致超时
Region 回收数量怎么被这个预测值决定
预测出“本次最多能花 MaxGCPauseMillis 对应的毫秒数”,再除以每个 Region 的历史平均回收耗时(也由 TruncatedSeq 维护),就得到本轮 Mixed GC 最多选几个 Region 进 CSet。但注意:
- 这个“每个 Region 耗时”不是固定值,而是按类型区分的:Eden Region、Old Region、Humongous Region 各自维护独立的
TruncatedSeq - 真正进 CSet 的 Old Region 数量,还受
-XX:G1MixedGCCountTarget和-XX:G1OldCSetRegionThresholdPercent限制,预测值只是上限,不保证一定用满 - 如果老年代碎片严重,或者 Humongous 对象扎堆,即使预测允许回收 20 个 Region,G1 也可能只选 8 个——因为剩下那些回收收益太低(垃圾少、跨 Region 引用多、RSet 扫描开销大)
为什么你看到的实际停顿常比 MaxGCPauseMillis 短,甚至波动很大
衰减预测模型只管“回收动作本身”的耗时,不包括 STW 阶段的初始标记(Initial Mark)和最终标记(Remark)——这两步时间取决于 GC Roots 大小和并发标记期间对象图变动量,完全不受 davg 控制。另外:
- Young GC 也共享同一套预测逻辑,但它的 Region 类型单一(基本全是 Eden),所以预测更稳;Mixed GC 混合多种 Region,
dsd天然更大,预测抖动更明显 - 一旦发生
Concurrent Mode Failure或退化为 Full GC,整个预测模型就失效了——这时候看的是内存压力,不是算法 -
TruncatedSeq默认只存最近 10 次数据,如果你的应用每小时才触发一次 Mixed GC,那模型几乎一直在用“过期数据”做决策

















