Eden区是新对象分配的入口,Survivor区是存活对象筛选通道且必须成对存在;双Survivor通过From/To角色互换实现无碎片复制;-XX:SurvivorRatio控制比例但非万能调参项;年龄计数仅在Survivor更新,晋升依据静态阈值与动态判定结合。

Eden区是对象出生地,Survivor区是存活对象中转站
Eden区承担新对象的首次内存分配,90%以上对象在这里创建、使用、消亡;Survivor区不接收新分配对象,只接收Minor GC后从Eden或另一个Survivor复制过来的存活对象。两者角色完全不对等:Eden是“入口”,Survivor是“筛选通道”。
Survivor必须成对存在,Eden不能单独和一个Survivor共存
如果只设一个Survivor区,Minor GC时需把Eden和该Survivor中的存活对象合并写入同一块空间,必然导致内存碎片——而JVM新生代GC要求零碎片、整块清空。双Survivor通过“From/To角色互换”机制规避这个问题:每次GC只向空的To区复制,From区和Eden区直接整块擦除。这个设计不是为了多存数据,而是为复制算法服务的基础设施。
Eden大小由-XX:SurvivorRatio控制,但不等于“可调优万能参数”
-XX:SurvivorRatio=8表示Eden : 单个Survivor = 8 : 1,即默认Eden占新生代80%。但调小这个值(比如设为2)会让Survivor变大、Eden变小,看似给存活对象更多缓冲空间,实际容易引发两个问题:
- Eden过小 → Minor GC更频繁,STW次数上升
- Survivor过大 → 年龄阈值未到但空间已满,触发提前晋升到老年代,加重老年代压力
真正需要调参的场景极少,常见于大对象突发、对象平均存活周期明显变长(比如缓存预热期),而非日常压测拍脑袋改值。
对象年龄计数器只在Survivor区更新,Eden里没有“年龄”概念
对象在Eden中无论活多久,只要没经历一次Minor GC,年龄就是0;只有成功复制进Survivor区,才会被标记为年龄1,并在后续每次从Survivor复制时+1。晋升老年代的条件是年龄≥<code>-XX:MaxTenuringThreshold(默认15),但注意:这个阈值只是上限,JVM还会动态计算“动态年龄判定”——当某次GC后,某个年龄的所有对象总大小超过Survivor空间的一半,这批对象会直接晋升,不管是否达到15。


















