I wondered if someone can explain the following behaviour to me.

For some reason, in the following code the instances of object Foo are
prevented from being garbage collected.

  def make_thread
    Thread.new { sleep 2 }
  end

  class Foo
    attr_accessor :bar
  end

  10.times { |i|
    f = Foo.new
    f.bar = make_thread
  }

  GC.start
  sleep 1
  GC.start

  ObjectSpace.each_object(Foo) { |o| p o }

But if I modify the code as follows, then the Foo objects are
garbage-collected just fine:

--- tst.rb      2008-09-17 10:00:27.000000000 +0100
+++ tst2.rb     2008-09-17 10:03:04.000000000 +0100
@@ -6,9 +6,10 @@
     attr_accessor :bar
   end

+  threads = (0..9).collect { make_thread }
   10.times { |i|
     f = Foo.new
-    f.bar = make_thread
+    f.bar = threads[i]
   }

   GC.start

It's as if the thread created by Thread.new keeps a reference to the Foo
object which existed at the time, even though inside make_thread it is
out of scope, so it shouldn't even know about it.

By tweaking the 'sleep' values, it also seems that when the thread
terminates it then does permit the Foo instance to be garbage-collected.

Any ideas as to what's going on? I get the same results on these two
versions of Ruby:

ruby 1.8.4 (2005-12-24) [i486-linux]
ruby 1.8.6 (2008-03-03 patchlevel 114) [i686-linux]

Thanks,

Brian.
-- 
Posted via http://www.ruby-forum.com/.