From: sheepman Date: 2001-11-22T20:27:50+09:00 Subject: [ruby-dev:15242] Re: gc.c (gc_mark_rest): declare work area as static On Thu, 22 Nov 2001 16:21:17 +0900 "K.Kosako" wrote: > 現在のGCのアルゴリズム(matz-sheepman)を少し変更しようと思って、 > テスト用スクリプトを書いているうちに、GCが永遠に戻ってこない > 現象を発見しました。(最新版です) > > gc_mark_rest()から再帰的に呼ぶ事のできるrb_gc_mark()の深さが、 > この現象が起こる場合、一段階だけになっているのが原因で永久に > 終わらないようです。 > 再現しました。 原因は、実際にマークする前にスタックの長さをチェックしていたからだと 思います。rb_gc_mark の制御の流れを整理したら直りました。 もとのコードでは、 マークしていないオブジェクトを発見→ マークする前にスタックの長さをチェック→ 溢れそうなので何もせずリターン→ マークしていないオブジェクトを発見.... (以下永遠にくり返し) となる可能性があったんですね。気づきませんでした。 # return の多用はプログラムの流れを分かり難くしますね。反省。 Index: gc.c =================================================================== RCS file: /src/ruby/gc.c,v retrieving revision 1.79 diff -u -r1.79 gc.c --- gc.c 2001/11/21 15:41:26 1.79 +++ gc.c 2001/11/22 11:15:28 @@ -464,7 +464,7 @@ while(p != tmp_arry){ p--; - rb_gc_mark(*p); + rb_gc_mark_children(*p); } } @@ -571,28 +571,25 @@ if (obj->as.basic.flags == 0) return; /* free cell */ if (obj->as.basic.flags & FL_MARK) return; /* already marked */ - if (!mark_stack_overflow){ + obj->as.basic.flags |= FL_MARK; + + if (mark_stack_overflow){ + mark_all &= 0; + }else{ int ret; CHECK_STACK(ret); if (ret) { if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) { *mark_stack_ptr = ptr; - mark_stack_ptr++; - return; + mark_stack_ptr++; }else{ mark_stack_overflow = 1; } + }else{ + rb_gc_mark_children(ptr); } - } - - obj->as.basic.flags |= FL_MARK; - - if (mark_stack_overflow){ - mark_all &= 0; - return; - }else{ - rb_gc_mark_children(ptr); } + } void -- sheepman / TAMURA Takashi sheepman@tcn.zaq.ne.jp http://www.tcn.zaq.ne.jp/sheepman/ Key fingerprint = 4E13 FE38 CD73 48D3 38AE 00EE 9E28 F98B D569 848E