Java堆中新生代与老年代比例由-XX:NewRatio=n决定,新生代=堆总大小÷(n+1),老年代=堆总大小×n÷(n+1);-Xmn会覆盖NewRatio;G1/ZGC下NewRatio失效;CMS中可能失效需用-Xmn;Survivor过小导致对象早晋升,应结合GC日志调优。

Java堆默认划分为新生代占1/3、老年代占2/3,这个比例不是固定值,而是由-XX:NewRatio参数动态决定的——它控制的是“老年代大小 ÷ 新生代大小”的比值,默认为2。
怎么算清楚新生代和老年代各占多少
别靠死记硬背,用公式直接推:设堆总大小为 -Xmx(比如 -Xmx4g),-XX:NewRatio=n,那么:
- 新生代大小 = 堆总大小 ÷ (n + 1)
- 老年代大小 = 堆总大小 × n ÷ (n + 1)
- 例如
-Xmx4g -XX:NewRatio=3→ 新生代 = 4GB ÷ 4 = 1GB,老年代 = 3GB
注意:-Xmn 参数会直接覆盖 -XX:NewRatio 的计算结果。一旦写了 -Xmn1g,不管 NewRatio 设多少都没用。
什么时候该调 NewRatio,什么时候该换 -Xmn
看你的调优目标是否需要“绝对可控”:
立即学习“Java免费学习笔记(深入)”;
- 想快速试不同比例(比如从默认2改成3)→ 用
-XX:NewRatio=3,省事、可比性强 - 部署环境堆大小固定(如
-Xms8g -Xmx8g),又要求新生代必须是整数GB(如2GB)→ 直接上-Xmn2g,避免算错或受JVM对齐策略干扰 - 用了G1或ZGC →
NewRatio基本失效,这些收集器自己管理分区,强行设了也忽略
特别提醒:CMS收集器下,-XX:NewRatio 有时会意外失效(尤其开启 -XX:+UseConcMarkSweepGC 后),这时必须用 -Xmn 显式锁定新生代大小。
Survivor区太小导致对象“早夭”晋升,怎么发现和修
现象很典型:Minor GC 频繁,但每次回收后老年代增长飞快,GC日志里 Promoted 字段数值异常高——说明大量对象没撑过一次GC就被塞进老年代了。
- 根本原因常是 Survivor 区不够用:
-XX:SurvivorRatio=8表示 Eden:Survivor=8:1:1,但如果新生代本身小(比如只有512MB),一个Survivor才约25MB,放不下存活对象 - 解决方法:要么调大新生代(
-Xmn),要么调大 Survivor 比例(-XX:SurvivorRatio=6,让每个Survivor占新生代 1/7 ≈14%) - 验证手段:加
-XX:+PrintGCDetails,看每次 Minor GC 后S0或S1的使用率是否长期 >90%
别只盯着 NewRatio,新生代内部结构失衡(Eden 太大、Survivor 太小)一样会把系统拖慢。
比例不是调出来就完事的,得结合 GC 日志里的 GC pause 时间、Promoted 量、Full GC 触发频率一起看;同一套参数在 Parallel GC 和 G1 下效果可能天差地别——配置项生效的前提,是它真的被当前垃圾收集器认了。










