Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Ruby C扩展的垃圾收集_Ruby_Garbage Collection_Ferret - Fatal编程技术网

使用Ruby C扩展的垃圾收集

使用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 =

我正在通过Ferret(Lucene的Ruby端口)代码来解决这个问题 虫子。Ferret代码主要是Ruby的C扩展。我遇到了 垃圾收集器存在一些问题。我设法把它修好了,但我 我不完全理解我的解决办法(我希望有人能更深入地了解我 了解Ruby和C扩展(这是我学习Ruby的第三天)可以 精心设计。谢谢

情况如下:

在费雷特C代码中,我向Ruby land返回了一个“令牌”。 代码看起来像

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垃圾收集器时,它有一个标记阶段和一个扫描阶段。标记阶段通过标记以下内容来标记系统中的所有对象:

  • ruby堆栈框架引用的所有对象(例如局部变量)
  • 所有全局可访问对象(例如,由常量或全局变量引用)及其子对象/引用对象,以及
  • 堆栈上引用引用引用的所有对象,以及这些对象的子对象/引用对象
  • 以及许多其他对本次讨论不重要的对象。然后,“扫描”阶段将销毁任何无法访问的对象(即未标记的对象)

    Data_Wrap_Struct返回对对象的引用。只要该引用可用于ruby代码(例如,存储在局部变量中)或位于堆栈上(由局部C变量引用),就不应扫描该对象

    从您发布的内容来看,令牌->文本正在被垃圾回收。但为什么会被收集?它不能被标记。标记对象本身是否被标记?如果是,则应标记标记标记->文本。尝试在令牌的mark函数中设置断点或打印消息以查看

    如果令牌没有被标记,那么下一步就是找出原因。如果它被标记,那么下一步就是找出text()方法返回的字符串被扫描的原因(可能不是被标记的同一个对象)

    另外,您确定是令牌的文本成员导致了异常吗?看看:

    我看到令牌和令牌流都有text()方法。TokenStream结构不包含对其文本对象的引用(它不能,因为它是一个不了解ruby的C结构)。因此,包装C结构的Ruby对象需要保存引用(这是通过rb_ivar_set完成的)

    RToken结构不需要这样做,因为它在其mark函数中标记其文本成员


    还有一件事:您可以通过在循环中显式调用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中引用以防止它被获取。谢谢