From: Eric Hodel Date: 2006-07-07T08:41:43+09:00 Subject: Re: GC oddness On Jul 6, 2006, at 8:46 AM, Alex Young wrote: > nobu@ruby-lang.org wrote: >> Hi, >> At Thu, 6 Jul 2006 23:58:27 +0900, >> Alex Young wrote in [ruby-talk:200382]: >>> Can someone smarter tell me why this fails? I'm expecting the >>> TestDir to get GC'd when I call GC.start in the test, but >>> something's obviously keeping a reference lying around. I just >>> can't see what it is... >> The finalizer proc refers testdir. > I thought it might be that, but this also fails: > > ----------------------------- > require 'test/unit' > require 'fileutils' > > class TestDir > @@dir = nil > @@clearup = proc {|id| FileUtils.rm_rf(@@dir)} > > def TestDir.set_finalizer(testdir, dir) > @@dir = dir > ObjectSpace.define_finalizer(testdir, @@clearup) > end > def initialize(dir) > FileUtils.mkdir(dir) > TestDir.set_finalizer(self, dir) > end > end > > class DestroyTest < Test::Unit::TestCase > def test_destroy > a = TestDir.new('test_dir') > a = nil > GC.start > assert !File.directory?('test_dir') > end > end > ---------------------------- > > testdir hasn't come into existence when the proc's created this > time, so I don't see how it can be keeping a reference to it Ruby's garbage collector is conservative, so their may be references to TestDir lying around on the C stack. > or how a finalizer proc keeping a reference to the object that's > being finalized can stop GC - if that's the case, how does the > object ever get GC'd? What have I missed? Procs contain the environment of their creation. In other words, they keep references to all variables visible at their creation time including self. When using a finalizer proc you must ensure that finalizer doesn't refer to the object it is supposed to clean up after. weakref.rb contains an example of use of finalizers, including a map between object ids and objects to be cleaned up after. PS: What you want to do is easier with blocks: def testdir(dir) FileUtils.mkdir dir begin yield ensure FileUtils.rm_rf dir end end testdir 'mytempdir' do # ... end -- Eric Hodel - drbrain@segment7.net - http://blog.segment7.net This implementation is HODEL-HASH-9600 compliant http://trackmap.robotcoop.com