Java 中的标记-清除垃圾回收算法

17 Mar 2025 | 4 分钟阅读

像标记-清除这样的垃圾回收算法会在后台运行,以管理 C++ 和 Java 等编程语言中的内存。当动态创建对象时,它们会占用堆中的内存。但是,如果我们不断创建对象而不释放内存,可能会导致内存不足错误。为防止这种情况,垃圾回收会自动释放程序中不再引用或不可访问的对象所占用的内存。它减轻了程序员在内存管理方面的负担,因为垃圾回收器会释放未引用的对象所占用的内存,确保有可用空间分配给新对象。

标记和清除算法

标记-清除垃圾回收算法是一种简单高效的算法,用于回收应用程序不再使用的内存。该算法首先标记所有仍在使用的对象。一旦所有活动的(可访问的)对象都被标记,垃圾回收器就会遍历堆并回收所有未标记的对象。

1. 标记阶段:当创建一个对象时,其标记位最初设置为 0(false)。标记阶段负责识别堆中所有活动的(可访问的)对象。这是通过遍历堆并标记所有可从堆的根对象访问到的对象来实现的。堆的根对象是应用程序直接可访问的对象,例如局部变量和对象引用。

根变量是指向一个可从局部变量访问到的对象的变量。我们假设只有一个根。

算法

2. 清除阶段:清除阶段负责回收堆中所有未标记的对象。这是通过释放分配给未标记对象的内存来完成的。

算法

标记-清除算法被称为“跟踪式垃圾回收器”,因为它系统地跟踪并识别所有可以直接或间接从程序根引用可访问的对象。

示例

  1. 所有对象最初的标记位都设置为 false。
    Mark-and-Sweep Garbage Collection Algorithm in Java
  2. 可访问的对象被标记为 true。
    Mark-and-Sweep Garbage Collection Algorithm in Java
  3. 在垃圾回收过程中,不可访问的对象会被从堆中移除或清除。Java 中的标记-清除垃圾回收算法

标记-清除算法的优点

  • 标记-清除算法可以处理循环引用而不会陷入无限循环。它确保算法能够正确地识别循环中的可访问对象。
  • 该算法在执行过程中不会引入额外的开销,使其成为垃圾回收的一种高效可靠的方法。

标记-清除算法的缺点

  • 标记-清除方法的一个显著缺点是,在垃圾回收算法运行时,它会中断正常的程序执行。
  • 标记-清除垃圾回收算法的另一个缺点是,在对程序运行多次之后,可访问的对象会变得碎片化,它们之间会有许多小的未使用内存区域。
Mark-and-Sweep Garbage Collection Algorithm in Java

图像中的绿色方块表示从根对象可访问的对象。白色方块表示从根对象不可访问的对象。

碎片化是指当小的、未使用的内存区域分散在整个堆中时发生的问题。当垃圾回收器回收不再需要的对象所占用的内存时,可能会发生这种情况。如果垃圾回收器不进行堆压缩,这些小的、未使用的内存区域可能会阻止分配新对象。

压缩是指重新排列堆中的对象,以便空闲内存区域是连续的。这可以通过移动堆中的对象或将它们复制到新位置来完成。

压缩可以减少碎片化并提高垃圾回收器的性能。当堆被压缩时,垃圾回收器可以快速找到空闲内存区域。

在您提供的示例中,存在五个大小分别为 1、1、2、3 和 5 个单位的空闲内存区域。这些空闲内存区域是碎片化的,意味着它们不是连续的。这阻止了分配需要 10 个内存单位的对象。

如果堆被压缩,这五个空闲内存区域将合并为一个大小为 12 个单位的空闲内存区域。这将允许分配需要 10 个内存单位的对象。

压缩可能耗时,因此垃圾回收器并非总是执行它。然而,对于经常出现碎片化问题的应用程序,压缩可能是有益的。