我在C中写了一个非侵入性的保守GC,我对它的堆栈扫描阶段的正确性有些担忧。
具体来说,没有启用编译器优化,它工作正常,因为每个局部变量(指向一个对象)在堆栈上“可预测地”分配。在-O3
中,GC错过了一些有效的引用,我认为这是因为编译器选择使用寄存器(而不是GC扫描的堆栈)来处理某些变量和函数参数传递以及GC (尚未)编程来处理这个问题。 (如果你怀疑这仍然不应该发生,并且我误解了问题的根源,请告诉我。)
除了一些基本要求(必须对GC对象使用GC_malloc
而不是malloc
,而不是从非GC堆指向GC堆,当然,不显式调用{ {1}}),GC不应再有来自客户端代码或编译器的任何要求。因此,不需要客户端代码中的任何其他特殊模式。类似地,强制使用此GC编译的程序使用特殊的编译器标志(抑制堆栈优化)应该是最后的选择。有了这两个,这就是我问题的积累。
我正在尝试找到一种方法让GC无缝地处理free
情况(使用堆栈优化)。这是我的思路(假设,更准确地说):
问题#1: 所有我的假设是否正确?
问题2:强制注册转储的最便携方法是什么?我发现一些消息来源声称一个简单的-O3
调用会产生这种效果。这是对的吗?
答案 0 :(得分:1)
Q1。是的,我相信你的所有四个陈述都是正确的(至少如果我们忽略了编译器错误!)
Q2。 setjmp将保存SOME寄存器,但不一定是所有寄存器。但是,它应该足以满足您的需要,因为任何未被setjmp保存的寄存器都应保存在堆栈中。
我猜你的方案可能会出错,如果有人在某个地方存储了一个看起来像地址的东西,即使它不是。
你还必须记住,有时人们用指针做“有趣”的事情。例如。
struct blah
{
size_t size;
char *file;
int line;
};
struct blah *p = malloc(sizeof(struct blah) + size);
... more lines of code goes here to fll in size, file and line in blah.
void *np = (p+1);
这意味着您存储的指针根本不指向块的开头。
答案 1 :(得分:1)
#1的一大问题是执行未定义(或可疑)的程序,但这通常有效。比如使用指针作为魔术常量来存储在文件中或通过网络连接发送并且通常在本地被遗忘,但随后它们可能会(从文件或网络)返回并在以后被取消引用。或旧的“xor prev和next pointers”技巧,用于链接列表,每个节点只有一个开销指针。