我有一个嵌入了ruby 1.9.3的win32控制台应用程序,我遇到了ruby GC和带有包含大数据指针的包装C结构的对象的问题。
经过一些测试,当孤立的对象占用一些内存时,ruby似乎会运行GC。问题是ruby没有考虑结构指针占用的内存大小,所以它不会启动GC,因为它认为那些孤立的对象太小而且不占用太多内存。
我制作了一个示例应用程序会崩溃,因为它在包装结构中创建了大量包含大数据的对象,这里是代码:
#include <ruby.h>
typedef struct TestClassStructS {
byte* bytes;
} TestClassStruct;
static void testClassFree(TestClassStruct *p) {
delete p->bytes;
delete p;
}
VALUE testClassNew(VALUE klass) {
TestClassStruct* ptr = new TestClassStruct();
ptr->bytes = new byte[1024 * 1024 * 5]();
VALUE obj = Data_Wrap_Struct(klass, NULL, testClassFree, ptr);
rb_obj_call_init(obj, 0, 0);
return obj;
}
VALUE testClassInitialize(VALUE self) {
return self;
}
typedef VALUE (*rubyfunc)(...);
VALUE require_wrap(VALUE arg)
{
return rb_eval_string("GC.enable; loop do; TestClass.new; end");
}
int main(int argc, char** argv[])
{
RUBY_INIT_STACK;
ruby_init();
//freopen("CON", "w", stdout);
ruby_init_loadpath();
ruby_sysinit(&argc, argv);
VALUE testClass = rb_define_class("TestClass", rb_cObject);
rb_define_singleton_method(testClass, "new", (rubyfunc)testClassNew, 0);
rb_define_method(testClass, "initialize", (rubyfunc)testClassInitialize, 0);
int error;
VALUE result = rb_protect(require_wrap, 0, &error);
if (error)
{
VALUE lasterr = rb_gv_get("$!");
VALUE message = rb_obj_as_string(lasterr);
printf(StringValuePtr(message));
}
return ruby_cleanup(0);
}
这不是一个真实的情况,但让我担心在某些情况下,如果GC未启动,我的应用程序可能会占用太多内存。
我可以解决这个问题,定期调用GC.start,但对我来说这似乎是一个肮脏的解决方案。
如果有一种方法可以让ruby在某些对象被孤立时优先处理垃圾收集,或者告诉ruby c struct在内存中占用的实际大小,这将是一个很好的解决方案,但我不知道ruby api是否包含某些内容像这样,我找不到那样的东西。
答案 0 :(得分:0)
如果可以,请使用xmalloc(我认为来自ruby.h)来分配内存。也就是说,到目前为止,唯一的方法是确保分配的内存占下一个GC触发器。
在包装的C结构中注册了一个新的dsize函数,但似乎它(但是?)在ruby 1.9.3中没有使用