【发布时间】:2019-07-31 04:44:55
【问题描述】:
我正在尝试实现一种小型脚本语言,并打算决定哪种垃圾收集算法适合我的优势。我选择了 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;我可以尝试释放它,但程序不允许。如果我为表中的每个变量都做这个,复杂性看起来很大(我对每个对象都有标记和扫描阶段)。
我的问题是我对 Mark & Sweep 算法是否正确?根是我的变量吗?如何删除多个指针甚至循环引用?
【问题讨论】:
-
Mark & Sweep 由两个阶段组成,就像它的名字一样。您需要实现 Mark 阶段 - 从根(您的变量)开始遍历所有可从它们访问的对象(您的元组和子元组)。以某种方式标记(一点就足够了)那些访问过的人。那些没有被标记的都是垃圾要被删除——在这种情况下通过清扫。
-
那么我对根源是正确的。但是,我需要一次又一次地扫吗?例如,变量 0(在示例中其名称为“x”)我打破了所有权并进行了扫描,之后再次对变量 1 进行相同的处理。在打破所有变量的所有权之前,我将进行如此多的扫描。我看不到这一点,因为看起来我要停下来收集垃圾。 @KonradKokosa
-
@fbgencer 每当垃圾收集器运行时,您都会进行标记和清除。什么时候或多或少取决于你。通常,只要内存消耗超过某个阈值,分配的内存就会调用 GC。许多系统还允许程序员手动调用 GC(尽管该功能不经常使用)。
标签: c garbage-collection programming-languages