2012-09-17 15 views
1

我有一個win32控制檯應用程序與紅寶石1.9.3嵌入式,我有問題的紅寶石GC和對象與包裝C結構包括一個指向大數據的指針。嵌入式紅寶石GC和包裝結構

經過一些測試後,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結構在內存中佔用的實際大小,這將是一個很好的解決方案,但是我不知道ruby api是否包含像這樣的東西,我找不到那樣的東西。

回答

0

如果可以,請使用xmalloc(來自ruby.h,我認爲)分配內存。也就是說,到目前爲止,確保分配的內存得到下一個GC觸發器的唯一方法就是解決這個問題。

沒有與包裝的C結構註冊一個新的DSIZE功能,但它似乎是不(沒?)的紅寶石1.9.3

+0

謝謝使用,這就行了。唯一的問題是如果你不控制內存分配(例如內存分配在外部庫中),你不能使用xmalloc。但也許我可以設法使其工作,可能通過改變一點點gc.c 你能指點我一些關於新的dsize函數的信息嗎? – vgvgf

+0

我有相同的一般問題(從C++分配的大結構,需要告訴Ruby的GC)。如果您對修補過的Ruby沒有問題,我會建議您簡單地添加一個公共方法,如rb_gc_announce_malloc(size)或類似的東西,它允許告訴GC有一些內存已分配。我不確定dsize方法。 –