Ruby拡張でVALUE*の配列に対してマーキングを行うにはどうすればよいですか?
-
12-12-2019 - |
質問
私は以下を含む行列型を持っています void*
すべてのC整数、すべての浮動小数点数、double、さまざまな構造体、または場合によってはすべてのRubyなど、指定された行列内の1つの型のすべてであるオブ VALUE
s)。
メモリ割り当てとガベージコレクションは、次の行列を作成しようとするまで正しく動作するようです VALUE
s.
私は次のmark関数を定義しています:
void mark_dense_storage(void* s) {
size_t i;
DENSE_STORAGE* storage = (DENSE_STORAGE*)s;
if (storage && storage->dtype == RUBY_OBJECT)
for (i = 0; i < count_dense_storage_elements(s); ++i)
rb_gc_mark(*((VALUE*)(storage->elements + i*sizeof(VALUE)));
}
だから、それは実際にある場合にのみマーキングを行います VALUE
行列—それ以外の場合, NULL
に渡されます Data_Wrap_Struct
マーク機能の場合。
しかし、私はいくつかをテストするときにsegfaultを取得しています VALUE
行列関数 (要点を参照).
具体的には、最初のオブジェクトでRubyメソッドを呼び出そうとしたときに初めてsegfaultようです VALUE*
配列:
C[i+j*ldc] = rb_funcall(C[i+j*ldc], nm_id_mult, 1, beta); // C[i+j*ldc] = C[i+j*ldc]*beta
nm_id_mult
私の中で定義されたグローバルです Init
として機能 rb_intern("*")
.
これはガベージコレクションの問題ではない可能性がありますが、GCは私が最も理解していないRubyの一部であり、私のsegfaultもほぼ同じです このトレース, これは、ポスターがGCに属性を付けます。
だから、私の質問:
それがGCの場合、配列をマークする適切な方法は何ですか
VALUE
s?GCでない場合、このタイプのエラーを診断するにはどうすればよいですか?私はそれのようなものを見たことがありません。
編集:
これは初期化に失敗した例であることが判明しました VALUE
Cで作成されたs.
言い換えれば、必ず次のようにしてください *(VALUE*)a = INT2FIX(0)
アクセスしようとする前に a
.
私はまだ質問が関連していると思います。私は、stackoverflowや他の場所で、クリーンアンドスイープガベージコレクションのマーキングの本当に良い例を見つけることができませんでした。あなたがそのような例や説明を提供することができれば、私はこの質問に対する正しい答えとしてそれをマークします。
解決
Rubyのmark-and-sweep GCは2つの段階で動作します。
最初のステージはライブオブジェクトをマークします。これは、既知の各「ライブオブジェクト」のマーキング関数を呼び出すことによって再帰的に機能します。ライブオブジェクトの初期セットは、既知の各Rubyスレッドまたは登録された各グローバルオブジェクトのCスタックをスキャンすることによって生成されます(「既知のライブ」オブジェクトを登録/登録解除するC関数があります)。オブジェクトXのマーキング関数は、xが参照する各オブジェクトに対してrb_gc_markを呼び出す必要があります。言い換えれば、あなたがすることはまさにあなたがすべきことです。
しかし、後で気づいたように、可能な値は有効なRubyオブジェクトではありません。しかし、私はQnilで初期化すると信じています(つまりnil)はもっとrubyっぽいでしょう。