define_finalizer

define_finalizer

refe

 ObjectSpace.define_finalizer
 --- ObjectSpace.define_finalizer(obj, proc)
 --- ObjectSpace.define_finalizer(obj) {|id| ...}
 
     obj が解放されるときに実行されるファイナライザ proc を
     登録します。同じオブジェクトについて複数回呼ばれたときは置き換えで
     はなく追加登録されます。
 
     proc には、ファイナライザとして Proc オブジェクトを渡
     します。ブロックを指定した場合は、そのブロックproc になり
     ます(しかし、後述の問題があるのでブロックでファイナライザを登録す
     るのは難しいです)。
 
     ファイナライザ proc には引数として obj の 
     ID(Object#id [Object/id]) が渡されます。
 
     以下は、define_finalizer の使い方の悪い例です。
 
         class Foo
           def initialize
             ObjectSpace.define_finalizer(self) {
               puts "foo"
             }
           end
         end
         Foo.new
         GC.start
 
     これは、渡された proc の self が obj を参照しつ
     づけるため。そのオブジェクトGC の対象になりません。
 
     tempfile.rb は、ファイナライザの使い方の
     良い例になっています。これは、クラスのコンテキストProc を
     生成することで上記の問題を回避しています。
 
         class Bar
           def Bar.callback
             proc {
               puts "bar"
             }
           end
           def initialize
             ObjectSpace.define_finalizer(self, Bar.callback)
           end
         end
         Bar.new
         GC.start
 
     proc の呼び出しで発生した大域脱出(exitや例外)は無視されます。
     これは、スクリプトのメイン処理が GC の発生によって非同期に中断され
     るのを防ぐためです。不安なうちは -d オプションで
     事前に例外の発生の有無を確認しておいた方が良いでしょう。
 
         class Baz
           def initialize
             ObjectSpace.define_finalizer self, eval %q{
               proc {
                 raise "baz" rescue puts $!
                 raise "baz2"
                 puts "baz3"
               }
             }, TOPLEVEL_BINDING
           end
         end
         Baz.new
         GC.start
 
         # => baz