一、核心垃圾回收算法
1. 标记 - 清除算法(Mark-Sweep)
核心思想:分为两个阶段 ——
标记阶段:遍历所有可达对象(从 GC Roots 出发能找到的对象),标记为 “存活”;
清除阶段:遍历堆内存,将未标记的对象(垃圾)回收,释放内存。
通俗比喻:整理房间时,先把有用的物品贴上标签(标记),再把没贴标签的杂物扔掉(清除)。
优缺点:
✅ 实现简单,无需移动对象;
❌ 会产生大量内存碎片(零散的空闲内存块),导致后续大对象无法分配;
❌ 效率低(两次全堆遍历)。
适用场景:极少单独使用,仅作为基础算法。
2. 标记 - 复制算法(Mark-Copy)
核心思想:将堆内存分为大小相等的两块(From 区、To 区),只使用其中一块(From 区);
标记阶段:标记 From 区的存活对象;
复制阶段:将存活对象复制到 To 区,按顺序排列;
交换阶段:清空 From 区,交换 From/To 区的角色。
通俗比喻:把房间分成 A、B 两半,只用 A 半放东西;整理时把 A 半的有用物品搬到 B 半并摆整齐,然后清空 A 半,下次用 A 半装新东西。
优缺点:
✅ 无内存碎片,分配内存时只需指针移动;
✅ 效率高(仅复制存活对象);
❌ 内存利用率低(仅 50%);
❌ 存活对象多的时候复制成本高。
适用场景:Java 新生代(Young Generation)的默认算法(如 Serial/ParNew GC),因为新生代对象 “朝生夕死”,存活对象少,复制成本低。
代码级理解(模拟逻辑):
// 模拟标记-复制算法的核心逻辑
public class MarkCopySimulator {
// 模拟堆内存的两个区域
private Object[] fromSpace = new Object[10];
private Object[] toSpace = new Object[10];
public void gc() {
int toIndex = 0;
// 1. 标记并复制存活对象到To区
for (int i = 0; i < fromSpace.length; i++) {
Object obj = fromSpace[i];
// 模拟:判断对象是否存活(从GC Roots可达)
if (isAlive(obj)) {
toSpace[toIndex++] = obj; // 复制到To区,按顺序排列
fromSpace[i] = null; // 清空原位置
}
}
// 2. 交换From/To区(简化版)
Object[] temp = fromSpace;
fromSpace = toSpace;
toSpace = temp;
// 清空To区
Arrays.fill(toSpace, null);
}
// 模拟判断对象是否存活
private boolean isAlive(Object obj) {
return obj != null; // 简化逻辑:非null即存活
}
}3. 标记 - 整理算法(Mark-Compact)
核心思想:在标记 - 清除的基础上增加 “整理” 阶段 ——
标记阶段:和标记 - 清除一致;
整理阶段:将所有存活对象向内存一端移动,然后直接清理边界外的所有内存。
通俗比喻:整理房间时,先标记有用物品,再把所有有用物品挪到房间一侧摆整齐,最后把另一侧的所有杂物一次性扔掉。
优缺点:
✅ 无内存碎片,内存利用率 100%;
❌ 整理阶段需要移动对象,耗时较长。
适用场景:Java 老年代(Old Generation),因为老年代对象存活率高,整理的收益大于成本。
4. 分代收集算法(Generational Collection)
核心思想:不是独立算法,而是基于 “对象存活周期不同” 的分代策略 ——
将堆分为新生代(Young)和老年代(Old):
新生代:对象创建和销毁频繁,用标记 - 复制算法(效率高);
老年代:对象存活时间长,用标记 - 整理算法(无碎片)。
新生代又细分为 Eden 区、Survivor 0 区、Survivor 1 区(比例通常 8:1:1),进一步优化复制效率。
通俗比喻:家里的垃圾桶(新生代)每天倒,用 “快速扔掉 + 重新摆” 的方式;储物间(老年代)半年整理一次,用 “归位 + 整体清理” 的方式。
核心流程:
新对象优先分配到 Eden 区;
Eden 区满时触发 Minor GC,存活对象复制到 Survivor 0 区;
下次 Minor GC 时,Eden + Survivor 0 的存活对象复制到 Survivor 1 区,清空 Eden 和 Survivor 0;
存活对象在 Survivor 区多次(默认 15 次)GC 后仍存活,进入老年代;
老年代满时触发 Full GC,用标记 - 整理算法回收,耗时远大于 Minor GC。
5. 分区收集算法(Region-Based Collection)
核心思想:将堆内存划分为多个大小相等的 “区域(Region)”,每次只回收部分区域,而非全堆扫描。
每个 Region 可独立进行垃圾回收,减少单次 GC 的停顿时间。
适用场景:G1 GC(Garbage-First)、ZGC、Shenandoah GC 等现代垃圾收集器,适合大内存(如 8G 以上)应用。
二、各算法对比表
总结
基础算法:标记 - 清除(简单但有碎片)、标记 - 复制(高效无碎片但浪费内存)、标记 - 整理(无碎片但耗时)是三大核心;
实战策略:分代收集是 Java 最基础的 GC 策略,新生代用标记 - 复制,老年代用标记 - 整理;
现代优化:分区收集(如 G1)是为了解决大内存场景下的 GC 停顿问题,是分代收集的进阶版。
这些算法的核心目标都是:高效识别并回收垃圾,同时最小化内存碎片和 GC 停顿时间。