使用Ruby C扩展的垃圾收集
我正在通过Ferret(Lucene的Ruby端口)代码来解决这个问题 虫子。Ferret代码主要是Ruby的C扩展。我遇到了 垃圾收集器存在一些问题。我设法把它修好了,但我 我不完全理解我的解决办法(我希望有人能更深入地了解我 了解Ruby和C扩展(这是我学习Ruby的第三天)可以 精心设计。谢谢 情况如下: 在费雷特C代码中,我向Ruby land返回了一个“令牌”。 代码看起来像使用Ruby C扩展的垃圾收集,ruby,garbage-collection,ferret,Ruby,Garbage Collection,Ferret,我正在通过Ferret(Lucene的Ruby端口)代码来解决这个问题 虫子。Ferret代码主要是Ruby的C扩展。我遇到了 垃圾收集器存在一些问题。我设法把它修好了,但我 我不完全理解我的解决办法(我希望有人能更深入地了解我 了解Ruby和C扩展(这是我学习Ruby的第三天)可以 精心设计。谢谢 情况如下: 在费雷特C代码中,我向Ruby land返回了一个“令牌”。 代码看起来像 static VALUE get_token (...) { ... RToken *token =
static VALUE get_token (...)
{
...
RToken *token = ALLOC(RToken);
token->text = rb_str_new2("some text");
return Data_Wrap_Struct(..., &frt_token_mark, &frt_token_free, token);
}
RToken *token = ALLOC(RToken);
token->text = rb_str_new2(tk->text);
/* added code: prevent garbage collection */
rb_ivar_set(input, id_curtoken, token->text);
return Data_Wrap_Struct(cToken, &frt_token_mark, &frt_token_free, token);
frt_token_mark调用rb_gc_mark(token->text)和frt_token_free
仅使用free(令牌)释放令牌
在Ruby中,此代码与以下内容相关:
令牌=@input.next
基本上,@input被设置为某个对象,调用该对象上的下一个方法
触发get_token C调用,该调用返回一个token对象
在RubyLand中,我然后执行类似于w=token.text.scan('\w+')的操作
当我在while 1循环中运行此代码(以隔离我的问题)时
某个时间点(大约当我的ruby进程内存占用达到256MB时,
可能是一些GC阈值),Ruby死后会出现如下错误
在终止的对象上调用的扫描方法
或者只是核心转储。我猜是token.text被垃圾收集了
我对Ruby C扩展了解得不够,不知道它会发生什么
数据包装结构返回的对象。在我看来,这项任务是用Ruby完成的
land,token=,应该创建对它的引用
我的“变通”/“修复”是在
对象,并将令牌文本存储在其中,以
获取对它的额外引用。所以C代码看起来像
static VALUE get_token (...)
{
...
RToken *token = ALLOC(RToken);
token->text = rb_str_new2("some text");
return Data_Wrap_Struct(..., &frt_token_mark, &frt_token_free, token);
}
RToken *token = ALLOC(RToken);
token->text = rb_str_new2(tk->text);
/* added code: prevent garbage collection */
rb_ivar_set(input, id_curtoken, token->text);
return Data_Wrap_Struct(cToken, &frt_token_mark, &frt_token_free, token);
现在我在输入实例变量中创建了一个“curtoken”,并且
在那里保存了文本的副本。。。我已注意删除/删除
此引用位于@input类的自由回调中
有了这段代码,我就不再得到终止的对象了
错误
这个修正对我来说似乎很有意义——它在curtoken中保留了一个额外的ref
添加到token.text字符串,以便不会删除token.text的实例
直到下一次调用@input.next(此时另一个
token.text替换curtoken中的旧值)
我的问题是:为什么它以前不起作用?不应该
Data_Wrap_结构返回一个对象,当在Ruby land中赋值时,
是否具有有效的引用,并且未被Ruby删除
谢谢。当调用Ruby垃圾收集器时,它有一个标记阶段和一个扫描阶段。标记阶段通过标记以下内容来标记系统中的所有对象:
还有一件事:您可以通过在循环中显式调用GC.start来重现这个bug,而不必分配太多的对象,这样垃圾收集器就会启动。这不会解决问题,但可能会使诊断更简单。可能会标记为易失性:
也许您的编译将引用保留在注册表中而不是堆栈中…我认为在README.EXT中提到了某种方法来强制对象永远不被GC'ed,但是…问题仍然是为什么要提前收集它…BTW,我猜在C中,当我返回数据包装结构时,我应该真正创建一个值变量,将其赋值为Data_Wrap_Struct的结果,并在某个位置保留该值变量的引用,这应该是返回值的常规惯例——您需要手动保留引用。我认为这是一个比我之前展示的更好的解决方案。但请评论。Paul:问题是当从C程序返回一个值到Ruby land时,应该做什么“正确的事情”。雪貂有:返回数据包装结构。。。在本例中,Data_Wrap_Struct返回的内容1)不在C堆栈上,因为它是从C过程返回的,2)不在Ruby对象中。我的修正不是“返回数据包装结构”,而是值v=数据包装结构。。。rb_ivar_集(..,和v);返回v;这就解决了问题。我想和某人确认一下:数据包装结构不能直接从C返回,但需要在Ruby obj中引用以防止它被获取。谢谢