2009年7月17日金曜日

Rubyの拡張モジュールでリソースを解放する方法

RubyはGCを持っているので、Rubyの世界の中ではリソースの解放をそれほど気にしなくてもよいけれど、Cで記述したRubyの拡張モジュールではそうはいかない。

インスタンス生成で資源を確保し、GCがインスタンスを回収した時に資源を解放するサンプル。

foo.c
#include <ruby.h>
#include <rubysig.h>

static VALUE g_cFoo = Qnil;

struct FooData
{
int x;
int y;
};

static void
Foo_free_data(struct FooData* data)
{
fprintf(stderr, "free 0x%08x\n", data);
#if defined(USE_RUBY_XMALLOC)
ruby_xfree(data);
#else
free(data);
#endif
}

static VALUE
Foo_alloc_data(VALUE self)
{
return Data_Wrap_Struct(self, 0, &Foo_free_data, 0);
}

static struct FooData*
Foo_data(VALUE self)
{
struct FooData* sval = NULL;
Data_Get_Struct(self, struct FooData, sval);
return sval;
}

static VALUE
Foo_initialize(VALUE self)
{
#if defined(USE_RUBY_XMALLOC)
DATA_PTR(self) = ruby_xmalloc(sizeof(struct FooData));
#else
DATA_PTR(self) = malloc(sizeof(struct FooData));
#endif
fprintf(stderr, "alloc 0x%08x\n", DATA_PTR(self));
return self;
}

Init_foo()
{
g_cFoo = rb_define_class("Foo", rb_cObject);

rb_define_alloc_func(g_cFoo, &Foo_alloc_data);
rb_define_method(g_cFoo, "initialize", &Foo_initialize, 0);
}

※注意!このモジュールを使って ruby 1.8.7 p174 {mingw32|linux}で ruby -rfoo -e 'loop{Foo.new}' したら Segmentation faultになった。原因不明>_<

0 件のコメント:

コメントを投稿