From: Robert Klemme Date: 2005-06-19T08:25:34+09:00 Subject: Re: GC.disable not working? Eric Mahurin wrote: > From what I can tell, GC.disable doesn't work. I'm wanting to > use GC.disable/GC.enable around code using objects that I get > from ObjectSpace._id2ref to make sure that the id doesn't > become invalid because of GC. Here is a piece of code that > demonstrates the problem: > > > #!/bin/env ruby > > def finalizer(id) > print("<") > GC.enable and > printf("GC disabled while finalizing %x!!!",id) > @ids.delete(id) > print(">") > end > > $stdout.sync=true > @ids = {} > 1000.times { |i| > print("[") > obj = "X"*i > id = obj.object_id > @ids[id] = true > ObjectSpace.define_finalizer(obj,method(:finalizer)) > GC.disable > print("{") > @ids.each_key { |id| > # go make sure all objects seem valid (test size) > ObjectSpace._id2ref(id).size > } > print("}") > GC.enable > print("]") > } > > > I tried this on 1.8.2 and a 1.9 CVS version. In both it calls > the finalizer when GC is disabled (GC.enable==true). Doesn't happen with the 1.8.2 I have. > I thought > this would be impossible. AFAIK there is just one guarantee: the finalizer is called *after* the object is GC'ed and before the interpreter exits. I don't know whether there are any guarantees that the finalizer is called *immediately* after the object was collected. So in theory the object could be collected while GC is enabled and the finalizer can be called some time later when GC is disabled. Although you might expect finalization to happen immediately after collection it would not be wise to require this of a runtime system as it might limit implementation choices in a way that negatively affect performance. > I also get a recycled object error. One reason for this could be that you iterate and manipulate the same collection (the Hash of oids) at the same time. Also, as I pointed out above - there is a time lag between collection and finalization. During this time the id is still in the hash but the object is gone already. > In the 1.9 version I'm using, it hangs while trying to finalize > one of the objects (@ids.delete(id) is where it hangs). You can avoid that by catching the exception: $ids = {} $stdout.sync=true fin = lambda {|oid| $ids.delete oid} 1000.times do obj = Object.new $ids[obj.object_id] = true ObjectSpace.define_finalizer(obj, &fin) obj = nil puts "disable: #{GC.disable}" $ids.each_key do |oid| begin raise "mismatch" unless ObjectSpace._id2ref( oid ).object_id == oid rescue Exception => e p [oid, e] end end puts "enable: #{GC.enable}" end > Any clues to what is going on with this GC stuff. If I can't > get this to work, I don't see how anybody reliably use > ObjectSpace._id2ref. BTW, I found this problem in my code > after running tens of thousands of random tests. If you don't > do enough testing, you may not find problems related to garbage > collection. Kind regards robert