From: Robert Klemme Date: 2005-06-21T02:25:35+09:00 Subject: Re: GC.disable not working? Eric Mahurin wrote: > --- Robert Klemme wrote: > >>> 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. > > Yep. Other than immediates, I believe an object id is just a > memory location. After an object is GCed, it will want to > reuse the space at some point. The new object may start at > that same location (same object id) or that location may > correspond to the middle of an object. So we have to look at the sources to get a definitive answer... >>> 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? > > I have tried Thread.critical= which is what Mutex and probably > other mutual exclusivity stuff are based on. The problem is > that GC/finalizers is not considered to be in separate threads. But in that case one of the two might help - the one that isn't reentrant, would it? > Nope. Still doesn't work. Try this: > > 100000.times { obj=Foo.new("hi") } > > The memory size just keeps growing and the obj's are not GCed. > In your second solution above obj isn't defined. I'm not sure > what you intended. obj = self - but then again, as you said it doesn't matter whether it's self or obj that keeps the instance alive. > The problem is that the Proc's you give to define_finalizer > still have access to the object you are putting the finalizer > on. This time through a local variable (obj) instead of self. > > You see why I say that the block form of define_finalizer isn't > useful? And should be removed? It dawns on me. :-) But wait: Robert@Babelfish2 /c/TEMP $ ruby gc3.rb > xx Robert@Babelfish2 /c/TEMP $ wc -l xx 10001 xx Robert@Babelfish2 /c/TEMP $ sort xx|wc -l 10001 Robert@Babelfish2 /c/TEMP $ fgrep -n end xx 10001:end Robert@Babelfish2 /c/TEMP $ cat gc3.rb def testit obj = Object.new ObjectSpace.define_finalizer(obj) {|oid| puts "cleanup #{oid}" } obj = nil end 10.times do 1000.times { testit } GC.start sleep 1 end puts "end" If you comment the "obj = nil" the binding is not modified and the instances are kept. The way it is here, instances are collected, which you can see from the "end" statement in the output IMHO. The trick is to use the local var and modify the binding afterwards. Also, the oids seem not reused (see the sort output). >> What is the real world problem you are trying to solve? > > In my cursor package, I create children cursors and need to > keep track of them. But, I don't want to keep a normal ref on > them so that they can't be garbage collected. For example: > > child = parent.postion # child holds the current position > parent.position? # any positions/children outstanding? > parent.position?(child) # is this a valid position? > parent.position! # kill positions/children > parent.delete1Next # update all children after this point > child.succ # next position - use with Range > > I don't want the user of this package to have to worry about > closing every single child. It would be a pain to have to do > this especially when intermediate expressions can yield a > child. I need to keep track of any outstanding, but I want GC > to get rid of any that aren't used anymore. A solution to tackle the oid reuse issue (if it's an issue) would be to store something that can verify that the oid belongs to the data stored for that oid. Unfortunately I can't think of a way ATM... Kind regards robert