From: Kouhei S. <ko...@co...> - 2011-12-17 13:52:12
|
須藤です。 In <CAMyNdeUg5F=HjS...@ma...> "Re: [ruby-gnome2-devel-ja] ID的なパラメータについて" on Fri, 16 Dec 2011 21:12:37 +0900, Masaaki Aoyagi <mas...@gm...> wrote: >>> 例えば、rbg_rval2cstrでは、StringValueをコールして、RSTRING_PTRでポインタを返しています。 >>> StringValueはhttp://doc.ruby-lang.org/ja/1.8.7/function/StringValue.htmlによると、 >>> GCから保護されるとのことなので、オブジェクトの開放はされずに残り続けると理解しましたが、 >>> リークしていることになるのでしょうか? >> >> あぁ、これは、関数の実行中はGCされない、くらいの意味です。 >> 関数がもろもろreturnしていって、Cの世界からRubyの世界に戻っ >> て、誰からも参照されなくなったらGC対象になります。 > > なるほど。ということは > * 通常、GVLでロックされているのでCの関数実行中はGCされることはない > * ただし、rb_thread_blocking_region?でGVLを意図的に外している場合はGCされうる > * その場合でも、StringValueで保護していればCの関数実行中はGCされない > みたいな事なんでしょうか?(ソース読んだことないから見当はずれっぽいなぁ) あぁ、そうではなく、単にスタック上にVALUEが置いてあればGCの ときにスタック上のVALUEをmarkしてくれるから大丈夫なんです。 怪しい時は VALUE ruby_object; ... RB_GC_GUARD(ruby_object); としておくと確実にmark対象になります。 なので、 > 以下のような感じで実装してみましたが、いかがでしょうか? > > #define RVAL2GLIBID(v) (rbg_rval2glibid(&(v), FALSE)) > #define RVAL2GLIBID_ACCEPT_NIL(v) (rbg_rval2glibid(&(v), TRUE)) > > const gchar * > rbg_rval2glibid(VALUE *value, gboolean accept_nil) 一応volatileを付けておいたほうがいいかなぁと思いました。 rbg_rval2glibid(volatile VALUE *value, gboolean accept_nil) たぶん、これで呼び出し元のVALUEがスタック上に残りやすくなる んじゃないかと思います。(volatileがどのくらい効くのかわかっ ていない。) > { > VALUE str; > gchar *id, *p; > > if (accept_nil && NIL_P(*value)) > return NULL; > > if (SYMBOL_P(*value)) { > str = rb_String(*value); 文字列への変換はStringValue()を使ったほうがいいです。 rb_String()だと何がなんでも文字列に変換するんですが、 StringValue()だとto_strがあるオブジェクトだけ文字列に変換し ます。 Ruby本体はto_strとか明示的な変換メソッドが定義されていない限 り暗黙的に変換しないのでそれに合わせたほうがよいと思います。 まぁ、今回はシンボル相手なのでどちらでも結果は変わらないので すが、一応StringValue()を使っていたほうがよいかと思います。。。 > } else { > StringValue(*value); > str = rb_str_dup(*value); > } > StringValue(str); /* 必要? */ これはRB_GC_GUARD(str)で十分だと思います。 > id = RSTRING_PTR(str); > for (p = id; *p; p++) > if (*p == '_') > *p = '-'; > > return id; あぁ、文字列を直接書き換えるんですかぁ。。。 であれば、ちょっとこの方向だとしんどいですね。。。 *valueを直接書き換えてもよければ、呼び出し元がVALUEを持つ (=スタック上に残る)のでこれでもいいんですが、*valueじゃな いstrに入れてるStringはこの関数を抜けたらスタックから消えて しまうのでrbg_rval2glibid()が返すgchar *がGCされてしまうかも しれません。 こんな感じでvalueの他にバッファ用のVALUEも別途受け取ってstr の代わりに使うように大丈夫そうな気がしますが、それだと使いづ らいですよねぇ。 http://d.hatena.ne.jp/nagachika/20111011/ruby_extension_library_howto_tmp_buffer あとは、const gchar *じゃなくてgchar *を返して呼び出し側で g_free()してもらうという案もありますが、そっちもひと手間増え ちゃいますよねぇ。 むぅ。 |