Java GC的常用算法

在 Java 中,垃圾回收(Garbage Collection,GC)是自动内存管理的核心机制,以下是几种常用的 Java GC 算法:

1. 标记 - 清除算法(Mark - Sweep)

  • 原理
    • 标记阶段:从根对象(如虚拟机栈中的引用对象、静态变量引用的对象等)开始遍历,标记所有可达对象。
    • 清除阶段:遍历整个堆,将未标记的对象(即不可达对象)所占的内存空间回收。
  • 优缺点
    • 优点:实现简单,不需要额外的空间。
    • 缺点:会产生大量的内存碎片,当需要分配较大对象时,可能无法找到足够的连续内存空间,从而导致频繁的垃圾回收。
  • 示例代码理解
public class MarkSweepExample {
    public static void main(String[] args) {
        // 创建对象
        Object obj1 = new Object();
        Object obj2 = new Object();
        // 使 obj1 变为不可达对象
        obj1 = null;
        // 此时垃圾回收器可能会在合适的时候使用标记 - 清除算法回收 obj1 占用的内存
    }
}

2. 标记 - 整理算法(Mark - Compact)

  • 原理
    • 标记阶段:与标记 - 清除算法的标记阶段相同,从根对象开始遍历,标记所有可达对象。
    • 整理阶段:将所有存活的对象(即标记的对象)向一端移动,然后直接清理掉端边界以外的内存。
  • 优缺点
    • 优点:解决了标记 - 清除算法产生内存碎片的问题,保证了内存的连续性,有利于大对象的分配。
    • 缺点:整理过程需要移动对象,会带来一定的性能开销。

3. 复制算法(Copying)

  • 原理
    • 将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
  • 优缺点
    • 优点:实现简单,运行高效,不会产生内存碎片。
    • 缺点:可用内存缩小为原来的一半,内存利用率较低。
  • 在 Java 中的应用:在新生代的 Eden 区和 Survivor 区的实现中使用了复制算法。一般来说,新生代内存会被分为一个 Eden 区和两个 Survivor 区(比例通常为 8:1:1),大部分对象在 Eden 区创建,当 Eden 区满时,会将存活的对象复制到其中一个 Survivor 区,当这个 Survivor 区也满时,会将存活的对象复制到另一个 Survivor 区或者老年代。

4. 分代收集算法(Generational Collection)

  • 原理
    • 根据对象的存活周期将内存划分为不同的区域,一般分为新生代和老年代。
    • 新生代:对象创建后大多会很快死亡,所以新生代采用复制算法进行垃圾回收。
    • 老年代:存活时间较长的对象会进入老年代,老年代采用标记 - 清除或标记 - 整理算法进行垃圾回收。
  • 优缺点
    • 优点:结合了不同算法的优点,提高了垃圾回收的效率。
    • 缺点:需要根据不同的代进行不同的配置,增加了系统的复杂度。
  • 示例代码体现分代思想
import java.util.ArrayList;
import java.util.List;

public class GenerationalGCExample {
    public static void main(String[] args) {
        // 模拟创建大量短生命周期对象,会在新生代分配内存
        for (int i = 0; i < 1000; i++) {
            Object obj = new Object();
        }

        // 模拟创建长生命周期对象,可能会进入老年代
        List longLivedObjects = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            longLivedObjects.add(new Object());
        }
    }
}
 
  

这些算法在不同的 Java 垃圾回收器中被组合和优化使用,以满足不同应用场景的性能需求。

你可能感兴趣的:(JVM,java,jvm)