对象分代年龄上限为15,是因为jvm对象头中mark word仅用4 bit存储该字段,最大值为2⁴−1=15;再多一位会挤占hashcode或锁状态等关键信息,且98%对象活不过首次minor gc,15次已足够标识长期存活对象。

对象分代年龄上限为15,不是经验设定,而是由JVM对象头的物理结构决定的——它直接卡在4个bit位上。
对象头里只留了4 bit给年龄
HotSpot JVM中,每个Java对象的对象头(Mark Word)在64位虚拟机下共8字节(64 bit)。其中专门划出4 bit用于存储分代年龄字段。这4 bit能表示的整数范围是0~15(二进制0000~1111)。再多一位都不行,因为其他bit已被严格分配给hashCode、锁状态、偏向线程ID等关键信息。就像身份证编号位数固定,多一位就得挤占出生日期或姓名栏——对象头也“寸土寸金”。
为什么刚好够用?统计和设计双重验证
- 98% 的对象活不过第一次 Minor GC,它们根本走不到“计龄”阶段
- 活过5次GC的对象占比约0.1%,活过10次的仅约0.01%
- 撑到15次还存活的对象,极大概率属于长期驻留对象(如缓存、单例、静态容器元素)
- 此时晋升老年代,既避免在Survivor区反复复制浪费CPU,又减少新生代GC压力
变量经历15次GC的真实含义
这里的“15次”指对象在新生代中成功躲过15轮Minor GC,并非自然时间跨度。具体过程是:
- 新对象诞生于Eden区
- Eden满触发Minor GC:存活对象移入Survivor(From),年龄设为1
- 下一次Minor GC:From中存活对象移入To,年龄+1;同时To与From角色互换
- 每完成一次“从一个Survivor复制到另一个Survivor”,年龄就加1
- 当年龄达到阈值(默认15),且当前目标Survivor空间足够,该对象被晋升至老年代
可以调成16吗?不行,硬性封顶
参数-XX:MaxTenuringThreshold允许你把阈值设为1~15之间的任意整数,但设成16或更高会被JVM静默截断为15,或启动时报错。这不是策略限制,是底层存储溢出风险防范——写入第5位bit会覆盖锁标志位或hashCode,导致对象状态错乱。所以15是不可突破的天花板。










