【发布时间】:2011-10-22 05:10:15
【问题描述】:
假设您正在将函数式语言编译为可移植的 C,并且还假设出于各种原因您想要精确而不是保守的垃圾收集。垃圾收集器没有可移植的方式(在一般情况下可能根本没有办法)来确定 C 堆栈上什么是指针,什么不是指针。在我看来,这个问题有两种解决方案:
影子堆栈。让每个 C 函数维护有关什么是指针和不是指针的簿记信息。这是例如推荐的方法。 LLVM。
利用您正在编译函数式语言这一事实,这意味着主线代码没有副作用。当分配器检测到内存不足时,它不会调用垃圾收集器本身,而是通过 longjmp 中止当前操作返回到调用垃圾收集器的主循环(在可能包含指针的变量集已知的上下文中)提前)然后重新开始操作。
在我看来,如果您正在处理适用于第二种方法的纯函数式语言,它必须比第一种方法更有效,并且更容易与手写 C 混合。
有没有我忽略的问题?有没有提到该技术的现有讨论或实现?
【问题讨论】:
-
可能没有帮助,但我在为我的方案解释器编写标记扫描时尝试了第一个。性能很差,所以我最终在 C 运行时堆栈之外建立了一个纯虚拟堆栈,主要是因为跨运行时堆栈自省几乎是不可能的。性能也很差,但没有 gdb/ddd 更容易调试。我决定凑合着用,因为这是解释器,并在我进入编译器实现阶段时处理它(通常从未完成)。
-
您打算如何重新启动当前操作?不时保存检查点,然后恢复上一个好的检查点(如何?)
-
@n.m.:在这方面问题的重要部分是“代码没有副作用”。提问者假设是一种纯函数式语言,因此不会修改任何状态。无需“采取”检查点,当您跳转到先前的状态时,您无需“撤消”任何更改,因为该语言无法进行更改。原则上,您在代码中的位置会告诉您有关程序状态的所有信息。
-
@n.m.这是个好问题。很容易想象一个字节码解释器,只需
longjmp回到eval()。但是对于编译,我不确定。您肯定不想在每次分配时都加上setjmps! -
@luser droog:或者您实际上可以在函数式语言中的函数每次返回后添加
setjmp。那是变量超出范围的时候,所以现在任何可收集的东西在最后一个这样的点上都是可收集的。提问者似乎只在主解释循环中建议setjmp,我认为这是因为它位于堆栈的顶部,并且他认为因此他不需要担心堆栈上的准确与保守标记。跨度>
标签: c compiler-construction functional-programming garbage-collection language-implementation