From: Alex Young Date: 2006-07-07T17:08:15+09:00 Subject: Re: GC oddness Eric Hodel wrote: > On Jul 6, 2006, at 8:46 AM, Alex Young wrote: > > ----------------------------- >> 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 >> ---------------------------- >> >> 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. That's what the code above ensures, I *think*... > weakref.rb contains an example of use of finalizers, including a map > between object ids and objects to be cleaned up after. Thanks, I'll take a look at that. > > 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 Unfortunately, that's not going to work here. What I'm trying to do is create a drop-in replacement for a small subset of Array's functionality which serialises its contents to disk rather than keeping it in memory, for some existing code. The idea is that a new instance creates a directory for itself on creation, and cleans up after itself when it gets GC'd. The existing code structure doesn't lend itself well to blocking. Of course, since everything gets GC'd on exit anyway, it's not exactly a huge problem, but it is making testing a tad tricky, and surprised me somewhat... -- Alex