GC算法核心目标是准确识别垃圾并高效腾内存:标记-清除易碎片,复制算法无碎片但空间利用率低,标记-整理解决碎片但需更新引用,分代收集则按对象年龄统筹调度,新生代用复制、老年代用标记-整理或标记-清除。

GC算法的核心目标就两个:准确识别不再使用的对象,再安全高效地腾出内存。不同算法在“怎么找垃圾”和“怎么腾空间”上各有取舍,没有万能方案,只有适配场景的选择。
标记-清除:最基础,但容易留下烂摊子
它分两步走:先从GC Roots出发,把所有能触达的对象打个标记;再扫一遍堆,把没标记的直接清掉。
- 优点是实现简单、不挪动对象,引用地址不变,开销小
- 缺点很实在:清完一堆零散空洞,内存碎片多——哪怕总空闲够大,也未必能塞下一个新对象,结果被迫提前触发更重的GC
- 而且堆越大,标记和清除越慢,Stop-the-World停顿时间就越明显
复制算法:新生代的快刀手
把内存切成两半(比如Eden + 一个Survivor),只用其中一块;回收时,把活着的对象一口气复制到另一半,原区域直接整块清空。
- 天然无碎片,分配新对象只需移动指针,极快
- 特别适合对象“活不久”的场景——JVM新生代里,90%对象撑不过一次Minor GC,复制量很小
- 代价是空间利用率受限:总得留一半备用,极端情况(比如全存活)还得靠老年代兜底
标记-整理:老年代的稳扎稳打派
在标记-清除基础上加一步:把所有存活对象往内存一端“归拢”,腾出连续大片空闲区,再清理尾巴。
- 彻底解决碎片问题,老年代对象寿命长、移动少,值得花这个成本
- 空闲空间管理变简单——只需记起始地址和长度,分配效率高
- 但对象一搬家,所有指向它的引用都得跟着更新,额外开销比复制算法还高
分代收集:把算法按对象年龄打包调度
它不是独立算法,而是统筹策略:根据对象存活时间,把堆划成新生代和老年代,各自选用最适合的回收方式。
- 新生代用复制算法——高频、轻量、快
- 老年代用标记-整理或标记-清除——低频、稳妥、抗碎片
- 背后有两个经验支撑:绝大多数对象朝生暮死;少数长寿对象基本不动
- 难点在于跨代引用处理,比如年轻代对象引用老年代对象,需要卡表(card table)或记忆集(remembered set)来加速扫描
实际JVM如HotSpot,就是以分代为骨架,把复制、标记-整理等算法组合落地。选哪种,关键看对象生命周期特征和系统对停顿、吞吐的侧重。

















