From: Robert Klemme Date: 2005-06-20T16:40:35+09:00 Subject: Re: GC.disable not working? Eric Mahurin wrote: > --- Robert Klemme wrote: >> "Robert Klemme" schrieb im Newsbeitrag >> def self.list >> FOOS.each do |oid, x| >> begin >> p ObjectSpace._id2ref(oid) >> rescue RangeError => e >> puts "#{oid} collected but not finalized: >> x=#{x.inspect}" >> end >> end >> end > > I assume you meant FOOS above. I fixed it. Correct. > Just catching a RangeError is not all you need. You better > make sure the object is finalized and the finalizer removes its > oid from FOOS before the space is reclaimed. Otherwise oid > could refer to a completely new object and you wouldn't detect > it. Probably. My assumption was, that oids are not reused. But I may be wrong here. > On top of that, these finalizers can't be called while this > FOOS.each loop is going on. Otherwise you'd get an error about > the hash being modified while your iterating over it. It is > like the GC and finalizers are in another thread, but > unfortunately you can't control it like a thread (i.e. > Thread.critical=). This is my primary dilemma. Hm... Did you try Mutex or Monitor? > These issues may be very difficult to detect problems with and > you may need 1000's of tests to excite the GC differently to > detect the problem. You must be prepared for this using > _id2ref. > >>> This approach works ok - you'll have to imagine that x contains >>> information needed for proper cleanup of a Foo instance, for >>> example, an open IO instance (although I'm sure that will do proper >>> cleanup on finalization): >>> >>> class Foo >>> FOOS = {} >>> >>> def initialize(x) >>> self.x=x >>> >>> ObjectSpace.define_finalizer(self) do |oid| >>> puts "Cleanup of #{oid} with #{FOOS[oid]}" >>> end >>> end > > Won't work. This is the exact mistake I made when first trying > to use a finalizer. In the above, you gave define_finalizer a > Proc that has a Binding with direct access to self (a Foo). > This creates an unintended reference to the object in > ObjectSpace/GC. It will never be GCed because of this. Darn, yes you're right! Two alternatives would be class Foo class< It > took me a while to figure this out. The Proc/Method needs to > be defined in a context that doesn't have access to the object > you are trying to put a finalizer on. For this reason, I don't > think define_finalizer should even allow the block form. Also, > a Proc#unbind would be nice to have in this situation. > > Also, I assume you'd want to delete the oid entry from FOOS in > this finalizer, right? Yes. Sorry for the errors and omissions - it was late already... > >>> def x=(y) >>> @x = y >>> FOOS[object_id] = y >>> end >>> >>> def x() @x end >>> end What is the real world problem you are trying to solve? Kind regards robert