分代收集的核心是按对象存活时间划分堆内存并匹配回收策略:年轻代用复制算法、高频minor gc(eden满即触发);老年代用标记-清除/整理、低频major/full gc(空间压力驱动);元空间按需清理类元数据,不参与常规gc。

分代收集的核心在于根据对象的存活时间特征,把堆内存划分为不同区域,并为每个区域设定匹配其对象生命周期的回收策略。关键不是“固定频率”,而是“按需触发+区域特性驱动”。
年轻代:高频率、小范围、快停顿
大多数新创建的对象都分配在年轻代(Eden区),它们中约95%会在几次GC后死亡。因此年轻代采用复制算法,回收频繁但耗时极短。
- 触发条件:Eden区空间不足时立即触发Minor GC
- 典型频率:应用负载高时每秒多次,空闲时可能几分钟一次——完全由对象分配速率决定
- 优化重点:调大Eden可降低Minor GC次数,但会增加单次处理对象量;需结合Survivor区大小避免过早晋升
老年代:低频率、大范围、重代价
长期存活的对象进入老年代,这里对象密度高、碎片多,回收成本显著上升。CMS或G1/ZGC等现代收集器已弱化“固定周期”,转而依赖空间占用和回收收益预估。
- 触发条件:老年代使用率达到阈值(如G1默认45%,CMS默认92%)或Minor GC后晋升失败
- 不依赖时间间隔,而依赖空间压力——即使数小时无GC,只要剩余空间充足就持续运行
- 避免人为设置“每X小时强制Full GC”,这反而破坏JVM自适应机制,易引发长时间STW
元空间(替代永久代):按需扩容,极少主动回收
元空间存放类元数据,直接使用本地内存,默认不限上限(受系统限制)。它不参与常规GC周期,仅在类卸载条件满足时被动清理。
- 回收时机:只有发生类卸载(如Web应用热部署、OSGi模块卸载)且元空间接近上限时才触发清理
- 通常无需干预;若频繁出现元空间OOM,应检查类加载泄漏,而非调整回收频率
- 可通过-XX:MetaspaceSize设初始阈值,避免早期频繁扩容,但不控制“多久回收一次”
跨代引用与卡表:让分代协作不拖慢速度
年轻代GC需扫描老年代到年轻代的引用(跨代引用),否则可能漏掉存活对象。JVM用“卡表(Card Table)”标记老年代中可能含跨代引用的内存块,大幅缩小扫描范围。
- 卡表是写屏障(Write Barrier)维护的位图,每次老年代对象修改引用字段时更新对应卡页
- Minor GC时只检查“脏卡”对应的老年代区域,跳过大量干净区域
- 这个机制让年轻代高频回收仍能保持低开销——没有它,分代设计就失去实际意义











