编译成C时的垃圾回收机制

20

将垃圾收集语言编译到C时,有哪些垃圾收集技术可用?我知道其中两种:

  1. 维护一个影子栈,显式地将所有根节点保存在数据结构中

  2. 使用类似Boehm的保守式垃圾收集器

第一种技术较慢,因为您需要维护影子栈。每次调用函数时,您可能需要将本地变量保存在数据结构中。

第二种技术也很慢,并且由于使用一个保守的垃圾收集器,本质上不会回收所有垃圾。

我的问题是:在将垃圾收集语言编译为C时,现在的垃圾收集技术水平如何?请注意,我不是指在C编程时进行垃圾收集的方便方法(这是Boehm的垃圾收集器的目标),而是指在 编译为C时 进行垃圾收集的方法。


2
这是一个棘手的问题。这也是为什么LLVM和C--等编程语言很受欢迎的原因(它们允许进行垃圾回收而无需手动处理)。 - user395760
源语言中的类型系统是基于DAG还是一般图形?DAG仅需要引用计数(由于是无环的)。 - Donal Fellows
一般的图形,不幸的是。我也考虑过引用计数,但这似乎并不能解决所有问题,因为你仍然需要一种遍历根节点以收集循环的方法... - Jules
编译成C是什么意思?你能给一个示例命令吗? - Ciro Santilli OurBigBook.com
1个回答

7

每次调用函数时,您可能需要将局部变量保存在数据结构中。

不必如此 - 您可以将局部变量保留在C堆栈上并仍然遍历它们:将所有引用变量放入数组中,并将指向该数组的指针添加到链表中,在进入新的堆栈帧时附加一个节点。

示意图:

struct vm
{
    struct scope *root;
};

struct scope
{
    struct scope *prev, *next;
    size_t size;
    struct ref *refs;
};

void foo(struct vm *vm, struct scope *caller)
{
    struct ref local_refs[42];
    struct scope scope = {
        caller, NULL, sizeof local_refs / sizeof *local_refs, local_refs };

    caller->next = &scope;

    // ...

    caller->next = NULL;
}

然而,如果您想支持continuations/non-local jumps,就必须跨越一些重要的障碍。在这种情况下,将所有内容堆分配会更容易。


当您将C作为编译器的目标语言来编译其他语言时,这种技术最为有用,因为它容易出错并需要仔细跟踪所有内容。 - Chris Dodd
谢谢,这是一个有趣的技巧。然而,这是否意味着局部变量不存储在寄存器中,这很可能比在调用时保存局部变量更慢? - Jules
@Jules:编译器仍然可以自由地将任何本地值缓存到寄存器中进行计算,但是你说得对,它必须在函数调用时同步这些值;我需要考虑如何适当使用“const”和“restrict”来告诉编译器被调用的函数不会修改本地变量,从而改善情况... - Christoph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接