Mixed GC 回收老年代 Region 的数量由动态预测模型决定:先满足并发标记完成和堆占用超IHOP阈值,再按“单位时间回收收益”排序贪心选取,受历史误差、老年代压力和全局轮数目标三重调节,并跳过高存活、巨型对象或RSet未就绪的Region。

要理解 G1 的 Mixed GC 是如何决定“这次回收哪些老年代 Region、收多少个”,关键不是看它“想不想收”,而是看它“能不能收、值不值得收、来不来得及收”。整个决策过程是动态的、预测驱动的、受多重约束的,核心目标是在满足停顿时间的前提下,逐步腾出老年代空间。
触发前提:并发标记必须完成,且堆占用跨过 IHOP 阈值
Mixed GC 不会凭空出现。它依赖两个硬性前提同时满足:
- 整个堆(年轻代 + 老年代)已用内存 ≥ InitiatingHeapOccupancyPercent(IHOP,默认 45%) —— 这是启动并发标记周期的开关;
- 该并发标记周期(含初始标记、并发标记、最终标记、清理)已完整结束 —— 只有清理阶段产出可回收 Region 排序后,Mixed GC 才可能执行。
这意味着:即使老年代用了 80%,只要总堆占用只有 40%,并发标记压根没启动,Mixed GC 就不会来;反过来,如果标记被频繁中断或取消(日志中出现 Concurrent Cycle was cancelled),哪怕堆已超 45%,Mixed GC 也迟迟不落地。
回收范围选择:按“单位时间收益”排序,贪心累加至停顿预算临界点
G1 不是随机挑老年代 Region,也不是平均分摊,而是构建一个价值优先队列:
- 每个老年代 Region 的回收价值 = (Region 大小 − 存活对象大小) / 预估回收耗时;
- 价值高的 Region 具备:垃圾占比高、存活数据少、RSet(记忆集)引用条目少、无大对象干扰;
- G1 在 Evacuation Pause 准备阶段,从高到低依次选取 Region 加入本次 CSet,直到预估 STW 时间逼近 MaxGCPauseMillis 设定值。
所以你看到日志里 [GC pause (mixed) 5 regions] 和 [GC pause (mixed) 12 regions] 交替出现,不是配置写错了,是 G1 正在根据实时成本模型动态调整。
数量调控杠杆:三个动态变量共同作用
单次选多少个老年代 Region,并非由某一个参数拍板,而是三股力量实时博弈的结果:
- 历史误差校正:若上轮实际停顿比预测长 20%,本轮就会主动减 Region 数;若连续两轮远低于目标,就试探多加 1–2 个;
- 老年代压力信号:当前老年代占用率比 IHOP 高出越多(如达 65%),G1 就越愿意放宽停顿限制,多选 Region 加速释放;
- 全局回收节奏控制:通过 G1MixedGCCountTarget(默认 8) 控制“预计总共几轮清完这批可回收 Region”,值越小,每轮压力越大,Region 数自然上升。
跳过与拒绝:不是所有老年代 Region 都能进回收集
即便排在价值榜前列,以下 Region 仍会被跳过:
- 存活对象占比 ≥ G1MixedGCLiveThresholdPercent(默认 85%) —— 复制开销大于收益;
- 属于巨型对象(Humongous)Region,且仍有活跃引用;
- RSet 过大,导致并发标记阶段未完成脏卡扫描,无法准确评估存活率;
- 当前剩余空闲 Region 不足,无法容纳待晋升/转移的对象(to-space exhausted 是严重预警信号)。

















