堆内存分代设计是用空间换时间,按对象生命周期分区管理以优化gc效率:新生代(eden+s0+s1)专收短命对象,通过minor gc快速清理;老年代存放长寿对象,触发full gc频率低但耗时长;比例可通过-xx:newratio等参数权衡吞吐与延迟。

堆内存的分代设计不是为了增加复杂度,而是用空间换时间——把对象按生命周期“分区管理”,让GC能快速清理大量短命变量,同时减少对长寿对象的无效扫描。
新生代:专为短命对象设计的快节奏战场
绝大多数对象(70%–99%)存活时间极短,刚创建不久就被弃用。新生代就是为这类对象量身打造的“快进快出”区域:
- 所有新对象默认在Eden区分配,这里不设引用检查,分配速度极快
- 当Eden填满,触发Minor GC:存活对象被复制到一个Survivor区(S0或S1),死亡对象直接丢弃
- 每次Minor GC后,两个Survivor区角色互换(From ↔ To),始终保证一个为空,避免碎片
- 对象每熬过一次Minor GC,年龄+1;默认达到15次(可通过-XX:MaxTenuringThreshold调整)就晋升至老年代
老年代:长寿对象的稳定栖息地
老年代不追求“快”,而追求“稳”。它存放的是那些经历多次GC仍被强引用的对象,比如缓存容器、连接池、Spring单例Bean等:
- 晋升条件除年龄外,还包括:大对象直接进入老年代(如超过-XX:PretenureSizeThreshold阈值的数组)
- Survivor区空间不足时,部分对象会提前“溢出”到老年代(动态年龄判定)
- 老年代GC(Major GC / Full GC)频率低但耗时长,通常采用标记-整理或标记-清除算法,暂停时间明显影响响应
- 一旦老年代也满了,且Full GC后仍无法腾出足够空间,就会抛出java.lang.OutOfMemoryError: Java heap space
空间博弈的关键:比例不是固定值,而是策略选择
新生代与老年代的空间配比,本质是吞吐量与延迟之间的权衡:
- -XX:NewRatio=2 表示老年代 : 新生代 = 2 : 1,即新生代占堆的1/3;适合长生命周期为主、GC压力偏小的场景
- 若系统大量创建临时对象(如JSON解析、日志拼接),可调大新生代(如-XX:NewRatio=1),减少Minor GC频次,但单次停顿可能略增
- -XX:SurvivorRatio=8 控制Eden : S0 : S1 = 8 : 1 : 1;若观察到Survivor区频繁溢出,说明对象存活率高,可适当调高Survivor占比或降低晋升年龄
- 注意:元空间(Metaspace)不在堆内,类加载过多不会导致堆OOM,但会引发OutOfMemoryError: Metaspace
识别真实瓶颈:别只看“谁占得多”,要看“谁拖得久”
监控时重点关注GC行为本身,而非静态内存占用:
- 高频Minor GC + 低晋升率 → Eden太小或对象存活率异常(如意外持有长引用)
- Minor GC后老年代持续增长 → 对象晋升过快,可能是Survivor空间不足或MaxTenuringThreshold设得太低
- 长时间停顿集中在Full GC → 老年代碎片化严重或存在内存泄漏(如静态Map不断put未remove)
- 使用-Xlog:gc*(JDK9+)或-XX:+PrintGCDetails收集日志,配合GCEasy等工具定位根因










