JVM垃圾回收采用分代+组合策略:新生代用复制算法(高效但受限于存活率),老年代用标记-整理或标记-清除,现代收集器如G1、ZGC则融合并发与增量技术以降低停顿。

JVM 垃圾回收算法不是“选一个最好的”,而是根据对象生命周期、内存分布和停顿要求,匹配最合适的回收策略。实际运行中,单一算法极少独立使用,主流 JVM(如 HotSpot)都采用分代+组合方式——新生代用复制算法,老年代用标记-整理或标记-清除,再辅以并发优化机制。
新生代:复制算法主导,高效但受限于存活率
新生代(Eden + Survivor)默认采用复制算法(如 Serial、Parallel GC 的年轻代收集)。它把内存划为 Eden、From、To 三块(比例常为 8:1:1),每次只用 Eden 和一块 Survivor。
- GC 触发时(如 Eden 满),仅扫描并复制存活对象到另一块 Survivor,然后清空原区域;对象年龄达阈值后晋升至老年代
- 优势明显:无碎片、分配快、STW 时间短,特别适合“朝生夕死”的场景(95%以上对象在一次 GC 后死亡)
- 局限也很直接:当 Survivor 空间不足或存活对象过多(比如长循环中缓存大量临时对象),会触发“担保失败”,被迫提前晋升或退化为 Full GC
- 内存利用率天然只有约 80%(Eden + 一个 Survivor 可用,另一个作复制目标),无法突破“半区闲置”瓶颈
老年代:标记-整理为主,平衡碎片与开销
老年代对象存活时间长、分布稀疏,复制成本过高,因此主流策略转向标记-整理(Mark-Compact)或带压缩的标记-清除(如 G1、ZGC 的混合回收)。
- 标记-整理先标记所有存活对象,再将它们向内存一端滑动压缩,最后清理边界外空间——既消除碎片,又避免复制全部存活对象
- 它比纯标记-清除更可靠(不会因碎片导致大对象分配失败),也比复制算法节省空间(无需预留等量空闲内存)
- 但移动对象需更新所有引用,带来额外开销;压缩过程本身耗时,STW 时间通常显著长于年轻代 GC
- 在 CMS(已废弃)中曾尝试用并发标记+清除规避 STW,结果因无法整理碎片,容易因碎片累积触发 Full GC,反而更不稳定
现代收集器:算法融合与增量并发成为关键
G1、ZGC、Shenandoah 等新一代收集器不再拘泥于传统算法边界,而是把标记、复制、整理、并发、增量等能力模块化组合。
- G1 将堆划为多个 Region,按回收价值优先清理,混合使用复制(跨 Region 移动存活对象)和整理(Region 内部紧凑),兼顾吞吐与延迟
- ZGC 和 Shenandoah 通过读屏障(Read Barrier)和染色指针等技术,实现大部分标记与转移操作与用户线程并发执行,STW 控制在 10ms 以内
- 但它们对硬件有更高要求(如 ZGC 需要着色指针支持、大页内存),且在极端高分配速率或超大堆(>1TB)下仍可能面临元数据压力或转移失败风险
- 这些算法虽大幅降低停顿,却增加了 JVM 内部复杂度和调优难度——例如 ZGC 的“中止周期”或 G1 的“并发模式失败”,往往源于参数配置与应用行为不匹配
算法选择不能脱离实际负载特征
再先进的算法,若脱离应用真实行为,也可能失效。比如:
- 大量长期缓存对象的应用(如风控规则引擎),老年代增长快、存活率高,若仍用默认 CMS 或 ParallelOld,易频繁 Full GC;此时更适合 G1 或 ZGC,并调大 InitiatingOccupancyFraction
- 短生命周期批处理任务(如 Spark Executor),年轻代 GC 频繁但单次极快,复制算法足够,反而是 GC 日志解析和元空间泄漏更需关注
- 响应敏感型服务(如网关、实时推荐),哪怕 50ms STW 也不可接受,就必须启用低延迟收集器,并配合对象复用、减少临时分配等编码习惯
- 堆外内存(DirectByteBuffer)、本地代码(JNI)、元空间(Metaspace)不受 GC 管理,算法再强也无法回收——这类泄漏常被误判为 GC 失效

















