g1垃圾回收器通过动态数学期望实时估算region回收耗时,再按收益排序累加至停顿上限确定cset;其期望值由指数加权平均(α=0.9)更新,并叠加衰减标准差与置信因子构成保守区间估计。

G1 垃圾回收器不依赖静态阈值或固定规则来决定单次回收范围,而是用一套以动态数学期望为核心的实时估算机制——它把每个 Region 的回收行为看作一个随机过程,用带权重的统计量逼近其真实耗时分布,并据此反推“在目标停顿内最多能安全处理多少个 Region”。
这个过程不是算一次总期望值,而是逐 Region 累积预估,直到逼近 MaxGCPauseMillis 上限。
动态数学期望怎么算出来的?
G1 对每个关键操作维度(扫描时间、复制时间、RSet 更新耗时等)都维护独立的指数加权平均(EWMA)序列,也就是一种动态数学期望估计:
每次实测某个 Region 的某项耗时(如扫描用了 4.2ms),就按公式更新: 新期望 = α × 当前实测值 + (1 − α) × 旧期望
其中 α 默认为 0.9,意味着最近一次观测占 90% 权重,历史趋势只留 10% 影响。这个期望值不是孤立存在的,还会叠加衰减标准差(dsd) 构成保守预测: 最终预测耗时 = MAX( davg + 0.5 × dsd , davg × confidence_factor )
——样本少时 confidence_factor > 1(冷启动阶段拉高预估值),波动大时靠标准差兜底。
所以它不是一个点估计,而是一个带置信缓冲的动态区间估计,天然适配 Java 应用内存行为的突变性。
单次回收范围怎么由这个期望决定?
G1 不是先定数量再验证,而是边选边累加,全程基于动态期望做决策:
- 并发标记完成后,G1 已知每个老年代 Region 的存活对象大小 → 可算出可回收空间
- 结合该 Region 历史 EWMA 耗时(含 RSet 复杂度校正),得出单位时间回收收益 = 可回收空间 ÷ 预测耗时
- 所有候选 Region 按该收益从高到低排序
- 从头开始累加每个 Region 的预测耗时期望值,一旦累计值接近
MaxGCPauseMillis(比如达 95%),立刻停止 —— 这些 Region 就构成本次 CSet
例如:目标 200ms,前 5 个 Region 预估耗时分别是 32ms、28ms、35ms、26ms、38ms,累加到第 5 个已达 159ms;第 6 个预估 45ms,加上就超限,于是本轮只收前 5 个。
实际中哪些情况会让这个期望“不准”?
- Survivor 区对象年龄集体跳升,导致复制开销远超历史 EWMA → 模型还没学够新样本,预测偏低
- 突发大量跨代引用,RSet 扫描暴涨,但 RSet 更新的 EWMA 更新滞后
- Humongous Region 被强制回收(未走并发标记流程),模型根本没它的历史数据
- 刚启动时样本不足 5 次,confidence_factor 高达 2.5,预测严重偏保守
这些都不是模型缺陷,而是动态期望对“数据新鲜度”的诚实反馈。
不复杂但容易忽略。











