新生代复制算法的停顿时间主要取决于是否有足够干净、连续的空间接收存活对象,而非搬运数据量;survivor区必须对称固定,大小由-xx:survivorratio控制,破坏对称性会导致gc异常或提前晋升;新生代大小影响minor gc频率与单次压力,过大或过小均可能引发频繁gc或担保失败导致full gc;survivor容量不足会触发空间分配担保机制,若老年代无足够连续空间则退化为full gc,造成百毫秒至秒级停顿;对象年龄仅在跨survivor复制时增加,晋升受survivor容量制约,盲目调优年龄阈值不如监控gc日志中的survivor used和promoted字段有效。

新生代复制算法的停顿时间,主要不取决于“搬了多少数据”,而取决于“有没有足够干净、连续的空间来接收存活对象”。空间配置不合理,会直接触发额外晋升、担保失败或频繁GC,把本该毫秒级的Minor GC拖成百毫秒级停顿。
Survivor 区大小必须对称且固定
S0 和 S1 不是可选配件,而是复制算法安全运行的基础设施。二者大小严格相等,由 -XX:SurvivorRatio 控制(例如设为 8,表示 Eden:S0:S1 = 8:1:1)。JVM 启动后结构即固化:
- 不能只禁用 S0 或只调大 S1——破坏对称性会导致 GC 异常或对象提前晋升
- 单 Survivor 区无法支撑复制:Eden 满时,需同时搬运 Eden + 当前 Survivor 的存活对象,但只有一个 Survivor 就没地方放,必然覆盖或失败
- 日志中看到 S0 used 从 0% 跳到 45%、S1 从 45% 降到 0%,就是轮转发生的直接证据
新生代总大小决定 Minor GC 频率与单次压力
新生代越小,Eden 区越快填满,Minor GC 就越频繁;新生代过大,单次 GC 需复制的存活对象可能陡增,尤其当 Survivor 空间不足时:
- -XX:NewRatio 控制老年代与新生代比例,默认值通常为 2(即新生代占堆的 1/3)
- 若应用创建大量短期对象,可适当减小 NewRatio(如设为 1),扩大新生代,降低 GC 频率
- 但盲目扩大新生代可能让本该在年轻代回收的对象滞留更久,反而增加 Survivor 压力和动态年龄判定触发概率
Survivor 容量不足会引发连锁停顿风险
当一次 Minor GC 后,存活对象总量超过一个 Survivor 区容量,就会触发“空间分配担保”机制:
- JVM 尝试将溢出部分对象直接晋升到老年代
- 但晋升前提:老年代剩余连续空间 ≥ 晋升对象预期总量(依据历史晋升均值估算)
- 若不满足,会退化为 Full GC——这才是真正导致数百毫秒甚至秒级停顿的元凶
- 动态年龄判定也会被激活:比如 S1 中所有 age=3 的对象总和超 S0 容量一半,所有 age≥3 对象立刻进老年代,加速老年代填充
对象年龄与晋升阈值不是硬编码的保险丝
对象年龄只在跨 Survivor 复制时加 1(Eden→S0 是第 1 次,S0→S1 是第 2 次……),但晋升并不死守默认阈值 15:
- -XX:MaxTenuringThreshold=0 相当于关闭 Survivor 缓冲,所有存活对象下轮就进老年代,极易诱发 Full GC
- 真正影响停顿的是“是否被迫提前晋升”:Survivor 小 → 年龄未到就被挤出去 → 老年代快速碎片化或填满 → 触发 Full GC
- 观察 GC 日志中的 “PSYoungGen” 段 before/after,重点关注 Survivor used 变化和 promoted 字段,比单纯调年龄阈值更有效











