4

我正在使用我正在研究的简单脚本语言 API 实现标记和清除垃圾收集,并且一直在阅读有关垃圾收集的各种实现的信息。诸如 Lua 之类的 API 对白名单、灰名单和黑名单使用标记和清除。

问题是,我似乎无法解释为什么会有这样的列表以及为什么将它们放入这些特定的颜色中。

在我当前的简单实现中,我只是使用“死”或“活”状态。在扫描中,死对象被删除。我正在使用本机堆,所以我没有在我的 GC 中做任何移动。

我正在用 C 编写它。

// Performs a full garbage collection
void GorCollect(GorContext *ctx)
{
    Value *v, *end;
    Collectable *c, *n;

    // mark stack references
    end = ctx->stack + ctx->stackTop + 1;
    v = ctx->stack;
    while(v != end)
    {
        if (gvisgc(v) && v->v.gc) // mark if a collectable obj
            Mark(v->v.gc);
        v = v++;
    }

    // mark global references
    if (ctx->global)
        Mark((Collectable *)ctx->global); // ctx->global is a collectable obj

    // perform sweep
    c = ctx->gchead; // full list of collectable objs
    ctx->gchead = 0;
    while(c) {
        n = c->next;    
        // destroy unmarked collectable
        if (!c->marked)
            FreeCollectable(ctx, c);

        // rebuild gc list (singly-linked)
        else
        {
            c->marked = 0;
            if (!ctx->gchead)
                c->next = 0;
            else
                c->next = ctx->gchead;
            ctx->gchead = c;
        }
        c = n;
    }
}
4

2 回答 2

8

灰色表示“活动但未扫描”:尚未将灰色块的所有后代标记为黑色。在增量垃圾收集器中,灰色是必需的。它有助于标记和清除 GC 在下次有机会做一些标记时继续它正在做的事情。

如果您的 GC 是非增量的,那么您可能会觉得您不一定需要灰色:您可以简单地总是递归您遇到的任何活动块的所有孩子。然而,另一个更微妙的问题是这种幼稚的非增量递归算法可能会溢出堆栈。灰色还有助于在堆而不是堆栈中存储有关下一步要访问的内容的信息。

即使您为此目的使用灰色,它也不会阻止您保留为提高效率而需要访问的块缓冲区。与朴素递归实现的唯一区别是当缓冲区已满时停止更新缓冲区,如果缓冲区在已满后变为空,则线性扫描堆以查找灰色对象。

于 2012-02-15T05:45:56.970 回答
0

首先,它们是集合,而不是列表,并且堆中的每个对象在任何时候都恰好在其中一个集合中。

其次,在任何标记和清除实现中都使用它们,但它们可能是隐含的。您没有提供 的实现Mark,但在该函数中,您正在移动集合中的对象。

这是我的垃圾收集器的标记阶段的实现:

/* Initally, the white set contains all objects, the black and
   grey sets are empty. */
stack *st = m->mark_stack;
/* First all roots are added to the gray set. */
for (size_t i = 0; i < m->roots->used; i++) {
    ptr p = m->roots->array[i];
    if (p != 0) {
        /* Mark the root and move it to the gray set. */
        AT(p) |= 1;
        st_push(st, p);
    }
}
while (st->used) {
    /* Think of popping the object from the mark stack as moving
       it from the gray to the black set. */
    ptr p = st_pop(st);
    P_FOR_EACH_CHILD(p, {
        if (!GET_MARK(p_child)) {
            /* Then mark each non-black child and move it to the
               gray set. */
            AT(p_child) |= 1;
            st_push(st, p_child);
        }
    });
}
/* When control has reached this point, the gray set is empty and
   the whole heap has been divided into black (marked) and white
   (condemned) objects. */

我们可以改为对这三个集合使用显式数据结构。但是对于一个停止世界的标记和扫描 gc,这个实现要高效得多。

于 2016-04-19T21:48:42.733 回答