From: Koji Arai Date: 2001-04-23T02:22:14+09:00 Subject: [ruby-dev:13021] Re: [rubyist:0523] Re:Re:finalizer での例外 新井です。 rubyist から移動 In message "[rubyist:0523] Re:Re:finalizerでの例外" on 21 Apr 2001 16:10:10 +0900, Koji Arai wrote: > 新井です。 > > ですよね。finalizerとして与えたブロックから参照できるローカ > > ル変数objに登録対象のオブジェクトが格納されているので、 > > finalizersからobjへの参照が発生し、結果としてobjがgcで回収さ > > れなくなるんです。やはりfinalizersは使い方が難しいですね。 > > なるほど、言われてみれば単純な話でした(でもやっぱり難しい)。 一応、Proc が持つ frame が self を保持しているからファイナラ イザが呼ばれないという認識も正しいようですね。 > ちゃんと調べてないのですがこの Bar でも終了時は、finalizer が > 呼ばれるのはなんでだろう? 調べたところ、逆でした。GC されなくても終了時には必ずファイ ナライザは呼ばれるのですね。 Baz で 終了時にファイナライザが呼ばれないように見えるのは gc.c rb_gc_call_finalizer_at_exit() 1249 for (i = 0; i < heaps_used; i++) { 1250 p = heaps[i]; pend = p + HEAP_SLOTS; 1251 while (p < pend) { 1252 if (FL_TEST(p, FL_FINALIZE)) { 1253 FL_UNSET(p, FL_FINALIZE); 1254 p->as.basic.klass = 0; 1255 run_final((VALUE)p); 1256 } 1257 p++; 1258 } の 1254行 で klass を消しているため eva.c:rb_call() 4450 if (!klass) { 4451 rb_raise(rb_eNotImpError, "method call on terminated object"); 4452 } で引っかかってるようです。これは意図したものなのなのでしょうか? 1.6.2 ではオッケーなので、 $ cvs diff -p -rv1_6_2 gc.c | --- gc.c 2000/12/22 03:21:56 1.48 | +++ gc.c 2001/04/19 09:16:07 1.48.2.13 | @@ -1044,6 +1063,7 @@ os_live_obj() | case T_CLASS: | if (FL_TEST(p, FL_SINGLETON)) continue; | default: | + if (!p->as.basic.klass) continue; | rb_yield((VALUE)p); | n++; | このあたりの副作用なのかなと想像するのですが。はずしてたらご めんなさい。 class Baz def initialize ObjectSpace.define_finalizer(self) { puts "baz" } end end class Bar def Bar.final(obj) ObjectSpace.define_finalizer(obj) { puts "bar" } end def initialize Bar.final(self) end end Bar.new Baz.new GC.start # ruby -d で実行 # ruby 1.6.4 (2001-04-19) [i586-linux] # ruby 1.7.0 (2001-04-02) [i586-linux] # => Exception `NotImplementedError' at -:4 - method call on terminated object # bar # ruby 1.6.2 (2000-12-25) [i586-linux] # => baz # bar -- 新井康司 (Koji Arai)