Java对象进入老年代由JVM动态决定:年龄达标(默认15次Minor GC,可调)、大对象直接分配(-XX:PretenureSizeThreshold)、Survivor空间不足时触发分配担保晋升,以及空间分配担保机制预判老年代容量。

Java对象进入老年代不是靠“时间”或“手动指定”,而是由JVM在垃圾回收过程中,根据对象的存活状态、大小和内存布局动态决定的。核心逻辑围绕“分代假设”:绝大多数对象朝生夕死,只有少数长期存活或体积过大者才需要挪到老年代。
年龄达标就晋升
新对象先分配在Eden区。每次Minor GC后,存活对象被复制到Survivor区(S0或S1),并年龄+1。默认年龄阈值是15,即经历15次Minor GC仍存活,下一次GC时就会进入老年代。
这个阈值可调:-XX:MaxTenuringThreshold=10 就变成10次;但实际晋升年龄可能更低——JVM会动态计算:如果Survivor中某一年龄段的对象总大小超过该区一半,所有≥该年龄的对象立即晋升,取这个动态值和MaxTenuringThreshold中的较小者。
大对象绕过新生代
特别大的数组、长字符串等,复制成本高、易碎片化,JVM干脆不走Eden→Survivor流程。
立即学习“Java免费学习笔记(深入)”;
- 启用条件:设置-XX:PretenureSizeThreshold=4194304(即4MB)
- 注意:该参数仅对Serial和ParNew收集器生效
- 未设置时默认为0,所有对象都走常规路径
Survivor装不下,就地升级
Minor GC后,存活对象要统一搬进To Survivor区。但如果To区空间不足:
- 年龄小但数量多的对象,可能挤不进去
- 超出部分不管年龄多小,直接进老年代——这叫“分配担保”
- 常见于秒杀、批量导入等突发流量场景,容易触发意外晋升
老年代空间够用,才敢做Minor GC
每次Minor GC前,JVM会预判:万一Survivor放不下,老年代能不能兜底?判断分两步:
- 先看老年代最大连续空闲空间是否 ≥ 当前新生代全部对象大小 → 是,直接GC
- 否则,再看是否 ≥ 历次晋升到老年代的平均对象大小 → 是,尝试带风险的Minor GC;否,触发Full GC腾空间
这个机制叫“空间分配担保”,由-XX:+HandlePromotionFailure控制(JDK 6u24后默认开启)。
基本上就这些。晋升不是固定规则,而是JVM在效率、空间、稳定性之间做的实时权衡。










