-XX:MaxTenuringThreshold 设置过低(如1或2)会加速老年代填满,因短生命周期对象过早晋升,绕过Survivor筛选;而过高(如15)在Survivor空间不足时亦无效,需结合S0U/S1U使用率与新生代大小协同调优。

为什么 -XX:MaxTenuringThreshold 设置过低会加速老年代填满
默认值是 15,意味着对象在 Survivor 区经历 15 次 Minor GC 后才晋升到老年代。但若设成 1 或 2,哪怕只是短生命周期对象(比如一次 HTTP 请求产生的 DTO),也会在第二次 GC 后直接进老年代——这相当于把新生代当“中转站”,完全绕过 Survivor 的自然筛选机制。
常见错误现象:OldUsed 在几分钟内持续上涨,G1OldGen 或 ParOldGen 使用率逼近 90%,紧接着触发 Full GC;而 YGC 频次并不高,说明不是 Eden 溢出,而是晋升失控。
- 实际场景中,高吞吐 Web 服务若每秒生成 20MB 临时对象,Survivor 空间又偏小(比如仅 32MB),即使
MaxTenuringThreshold=15,也可能因 Survivor 无法容纳存活对象,提前触发“担保失败”(Promotion Failure),强制晋升 - 该参数只对 Parallel GC 和 CMS 生效;G1 收集器**忽略此参数**,改用动态年龄判断(
-XX:G1MaxNewSizePercent、-XX:G1MixedGCCountTarget等间接影响晋升) - 设置过高(如
15)也不一定好:如果 Survivor 空间太小,对象根本撑不到第 15 次 GC 就被挤出去了,此时参数形同虚设
如何结合 SurvivorUsage 判断是否该调大 MaxTenuringThreshold
关键不是拍脑袋设值,而是看 jstat -gc 输出里的 S0U/S1U(Survivor 使用量)和 EC/EU(Eden 容量/使用量)比值。若每次 Minor GC 后 S0U 长期稳定在 80%~95%,说明 Survivor 基本装满、对象“没地方待”,大概率下一轮就晋升——这时调大 MaxTenuringThreshold 没意义,得先调大 -Xmn 或调整 -XX:SurvivorRatio。
- 观察窗口建议取 5~10 次 Minor GC 周期,避开 GC 波动毛刺
- 若
S0U常低于 30%,且老年代缓慢增长,可尝试将-XX:MaxTenuringThreshold从默认 15 提到20或25,给对象多留几轮被回收的机会 - 注意:该参数必须配合
-XX:+UseParallelGC或-XX:+UseConcMarkSweepGC才生效;单独设置无效
Parallel GC 下的典型组合调优示例
假设你用的是 Parallel GC(即 -XX:+UseParallelGC),堆总大小 4G,观测到老年代每 8 分钟涨 300MB,Minor GC 间隔约 12 秒:
-Xms4g -Xmx4g -Xmn2g -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=20
解释:-Xmn2g 把新生代拉到 2G(占堆一半),-XX:SurvivorRatio=8 让 Eden : Survivor = 8 : 1(即每个 Survivor 约 125MB),再配合 20 的晋升阈值,让大多数对象有足够空间和轮次在 Survivor 中“自然死亡”。
- 不推荐把
MaxTenuringThreshold设到 50+:JVM 内部有硬限制(Parallel GC 最大支持 15,CMS 支持到 255,但超过 20 后收益急剧下降) - 如果应用大量使用
ThreadLocal或缓存短期对象,反而要**降低**该值(如设为5),避免 Survivor 区长期滞留“伪长命”对象,挤占真正需要多轮存活的空间 - 每次调整后必须观察至少 30 分钟的
jstat -gc输出,重点看OU(Old Used)增速是否放缓,以及YGCT(Young GC 总耗时)是否明显上升——后者说明 Survivor 太大、GC 扫描变慢,就得折中
G1 收集器下别白费劲设 MaxTenuringThreshold
-XX:MaxTenuringThreshold 对 G1 完全无效。G1 用的是动态晋升策略:它根据每轮 GC 后各 Region 的存活对象大小,自动决定哪些 Region 升为 Old,不依赖固定次数。强行设置该参数只会被 JVM 忽略,日志里也不会报错。
真想控制 G1 的对象晋升节奏,该盯这些:
-
-XX:G1NewSizePercent和-XX:G1MaxNewSizePercent:控制新生代弹性范围(默认 5%~60%),扩大新生代能延缓晋升 -
-XX:G1MaxNewSizePercent=40比单纯调MaxTenuringThreshold更有效 -
-XX:G1HeapWastePercent=5:当堆中可回收空间占比超 5%,G1 才启动 Mixed GC,间接减少老年代压力 - 用
-Xlog:gc*,gc+age=trace查看实际晋升年龄分布,比猜参数靠谱得多
最常被忽略的一点:对象是否大到直接进老年代,跟这个参数毫无关系。-XX:PretenureSizeThreshold 才管大对象分配,而它只对 Serial 和 Parallel GC 有效,G1 下同样失效——G1 用的是 Humongous Region 机制。










