对象进入老年代由四条并行路径决定:年龄达标(达maxtenuringthreshold默认15)、动态年龄判定(survivor中某年龄起累计≥50%即晋升)、空间担保失败(survivor装不下时提前晋升)、大对象直入(超pretenuresizethreshold阈值)。

对象进入老年代不是单一条件决定的,而是 JVM 根据堆内存实际使用状态动态判断的结果。真正起作用的,是四条并行生效的路径,其中三条依赖 Minor GC 的执行时机,一条可绕过新生代直接发生。
年龄达标:静态阈值只是理论上限
对象每经历一次 Minor GC 且仍存活,年龄 +1;刚从 Eden 复制到 Survivor 的对象年龄为 1。当年龄达到 -XX:MaxTenuringThreshold(默认 15)时,会晋升老年代。但注意:这个值只是“最大允许年龄”,不是“必须活满才走”。日常运行中,绝大多数对象根本等不到 15 次 GC 就已晋升——因为动态年龄判定更早触发了。
动态年龄判定:真正主导日常晋升的行为
每次 Minor GC 后,JVM 扫描当前 To Survivor 区,按年龄从小到大累加对象大小:
- 先加所有 age=1 的对象总大小
- 再加所有 age=2 的对象大小,累计值若 ≥ Survivor 总容量的 50%(由 -XX:TargetSurvivorRatio 控制,默认 50%),则 age≥2 的全部对象本轮晋升
- 该临界年龄即为本轮实际生效的晋升门槛,GC 日志中会明确打印:new threshold 2 (max 15)
这个阈值每轮都可能变化,它反映的是 Survivor 区真实的碎片与压力状况,比配置的 MaxTenuringThreshold 更敏感、更关键。
一款AI工具,主要用于自动分析崩溃并修复错误。监控 Cloudflare D1 崩溃报告,进行去重和 Codex 5.3 High 分析,生成修复并创建...,适合需要提升相关任务效率的用户。
空间担保失败:Survivor 装不下,就只能进老年代
Minor GC 过程中,Eden + From Survivor 的存活对象要一次性复制到 To Survivor。如果目标 Survivor 空间不足:
- JVM 先尝试把 age 较小的对象提前送入老年代,腾出空间
- 若仍不够,或 Survivor 区本身已严重碎片化,就会触发“担保失败”(promotion failed)
- 此时大量存活对象(包括 age=1 的新晋 Survivor 对象)会直接进入老年代
这种情况在 SurvivorRatio 设置过小(如设为 2)、或对象分配速率剧烈波动时极易发生。
大对象直入:跳过新生代,一步到位
满足以下任一条件的对象,创建时就不经过 Eden 和 Survivor:
- 对象所需连续内存 > -XX:PretenureSizeThreshold(如设为 3MB,则 4MB 数组直接进老年代)
- 常见类型:大数组(
new byte[4*1024*1024])、长字符串、大集合底层数组
设计初衷是避免大对象在 Survivor 区反复拷贝浪费 CPU 和带宽,也防止其挤占年轻代空间引发频繁 Minor GC。










