多个指针和标记和扫掠

时间:2019-03-09 08:05:25

标签: c garbage-collection programming-languages

我正在尝试实现一种小型脚本语言,并打算确定哪种垃圾回收算法符合我的利益。我选择了Mark&Sweep,但我认为我误解了这个概念。

假设调用了一个任意函数,它创建了以下变量(可能它们没有名称,但为简单起见,假定它们是在此函数中创建的)。

f() {
    /*f creates following variables*/     
    x = (1,2,(3,4,(5,6))); //this is tuple
    a = x;
    y = x[2];
    z = y[2];
    p = (10,y);
}

在上面的示例中,所有内容都是一个对象(整数,字符串,元组,双精度型等),并且元组保留指向其对象的指针。而且,每个对象都生活在堆中。当函数超出范围时,它必须删除分配的变量。功能范围如下所示。

+-----+
|     |
|  x  +---------->(1,2,+)
+-----+           ^    |
                  |    v
+-----+           |    (3,4,+)
|     |           |    ^    |
|  a  +-----------+    |    v
+-----+                |    (5,6)
                       |    ^
+-----+                |    |
|     |                |    |
|  y  +----------------+    |
+-----+                |    |
                       |    |
+-----+                |    |
|     |                |    |
|  z  +---------------------+
+-----+                |
                       |
+-----+                |
|     |                |
|  p  +----------->(10,+)
+-----+

所有变量(a,x,y,z,p)都必须删除,但问题是如何?我知道Mark&Sweep是垃圾收集算法,我认为这个变量现在是我的垃圾。函数已完成其工作,并且必须将分配的内存返回给系统。

我尝试了以下操作,每个对象都持有一个标记位,并且在创建标记位设置为0之后。当程序将一个变量所持有的对象推入时,它将其标记转换为1,并且不会发生自由错误,因为程序知道它有一个所有者。到目前为止,这种方法一直有效。但是,如果我有很多如示例中所示的变量,该如何删除多个指针?

在这里,我的假设是,首先打破x及其对象之间的所有权。然后说出每个变量以标记其对象(如果该对象是一个元组,则将其对象标记位递归设置为1)。现在(1,2,...)对象的标记位由变量'a'设置为1;我可以尝试释放它,但程序不允许。如果我对表中的每个变量都进行此设置,那么复杂性看起来就很大(我对每个对象都有标记和清除阶段)。

我的问题是我对“标记和扫频”算法是否正确?根是我的变量吗?如何删除多个指针甚至循环引用?

1 个答案:

答案 0 :(得分:1)

对于“标记并扫描”,您需要能够在一侧扫描所有分配的对象,在另一侧扫描所有可到达的对象。

  • 假定所有已分配的对象上的标记位均已清除,请扫描可从根变量访问的所有对象。找到对象后,如果已将其标记,则将其跳过,否则对其进行标记并递归枚举其指向的对象。此阶段很棘手,因为此递归可能会变得太深,因此需要比纯递归更聪明的方法。

  • 一旦所有可访问对象都被标记,请扫描所有已分配的对象:对于每个对象,如果已标记,请清除标记,否则它是不可访问的,因此请收集它(即:使其可重新分配或免费使用) )。

在Sweep阶段结束时,所有分配的对象都未标记,因此假设成立。一种效率稍高的实现方式将在两种状态之间交替,从而无需清除可到达对象上的标记位,从而减少了扫描阶段所需的内存带宽。

在程序的正常运行过程中更改对象引用时,不需要执行任何特殊操作:只需存储新引用的地址即可。

要有效地删除从全局变量引用的对象,您只需使这些变量指向null或其他对象即可。

Mark&Sweep的优点是该算法相对简单,并且能够按周期收集复杂结构。缺点是 stop the world 模式下花费的时间,尤其是在多线程应用程序和实时应用程序甚至用户交互应用程序中。已经找到了解决这些问题的更高级的方法,但是它们的实现可能非常棘手。