垃圾回收算法
2026/8/24大约 2 分钟
垃圾回收算法
四种经典 GC 算法的原理、优缺点与适用区域。
算法对比总览
| 算法 | 原理 | 优点 | 缺点 | 适用区域 |
|---|---|---|---|---|
| 引用计数法 | 对象被引用次数为 0 时回收 | 实现简单 | 无法处理循环引用 | 基本被淘汰 |
| 标记-清除 | 标记所有从根节点可达对象,清除未标记的 | 简单 | 内存碎片化,空间不连续 | 老年代(配合压缩) |
| 复制算法 | 内存分两块,存活对象复制到另一块,整块清除 | 效率高 | 内存折半 | 新生代(存活少、垃圾多) |
| 标记-压缩 | 标记-清除改进,存活对象压缩到内存一端 | 无碎片、不需双倍内存 | 移动对象开销 | 老年代 |
各算法详解
1. 引用计数法
每个对象维护一个引用计数器,被引用时 +1,引用失效时 -1,为 0 时回收。
致命缺点:无法处理循环引用——两个对象互相引用时,计数器永远不为 0,无法回收。
2. 标记-清除(Mark-Sweep)
- 标记所有从根结点(GC Roots)开始可达的对象
- 清除所有未被标记的对象
缺点:清除后会造成内存空间不连续,产生大量碎片;不连续内存空间工作效率低,不容易分配大对象内存。
3. 复制算法(Copying)
- 将内存空间分成两块
- 每次把正在使用内存中的存活对象复制到未使用的内存块
- 清除正在使用的整块内存
优点:算法效率高。 缺点:代价是系统内存折半。 适用:新生代——存活对象少、垃圾对象多,复制成本低。
4. 标记-压缩(Mark-Compact)
标记-清除的改进:
- 标记所有存活对象
- 清除未标记对象时,将所有存活对象压缩到内存一端
- 清理边界外所有空间
优点:既避免碎片产生,又不需要两块同样大小的内存块,性价比高。 适用:老年代。
分代收集
JVM 将堆划分为不同代,不同代使用不同算法:
| 分代 | 特点 | 算法 |
|---|---|---|
| 新生代 | 存活对象少、垃圾多 | 复制算法 |
| 老年代 | 存活对象多、生命周期长 | 标记-清除 / 标记-压缩 |