From: Garthy D Date: 2013-02-16T20:08:31+09:00 Subject: Re: Fun with finalizers Hi Matthew, Excellent thinking. I also thought it might be something along those lines too. I tried various combinations as well: proc, Proc.new, I think a return from method(), calls to a separate object; but there was no impact on the result. If "a" isn't cleared, the object is held. I'm guessing that there might be some way to say to not touch a thing in the current scope, but I'm not sure *how* to specify it. I also adapted the main program based on my experience with the code below, and suddenly the finalizers were called. So it's the same type of problem. So there's a problem, and it's avoidable. I know the "what", but don't know the "why". There is some subtlety I'm missing. Most interesting. :) Cheers, Garth On 16/02/13 20:30, Matthew Kerwin wrote: > Quick guess, it's the lambda. Replace it with #proc and try again? > > Sent from my phone, so excuse the typos. > > On Feb 16, 2013 4:39 PM, "Garthy D" > > wrote: > > > Hi all, > > Just ran into something very interesting with finalizers. I've found > a workaround (it'll be obvious what it is from the code below), but > I just thought I'd share it for discussion's sake. > > Consider the code below: > > $fcount = 0 > > class A > def initialize > end > end > > class B > > def initialize > end > > def bar a > ObjectSpace.define_finalizer(__a, lambda {|oid| $fcount += 1}) > a = nil # xxx > nil > end > > def foo > > a = A.new > bar a > nil > end > end > > b = B.new > for i in 1 .. 10000 > GC.start > b.foo > GC.start > end > $stderr.print "Program ends. #{$fcount} finalizers called.\n" > > All but one of the finalizers run at the point of the trace. > > Now, comment the line marked with xxx. This shouldn't make any > difference- but it does. The program will report that 0 finalizers > ran at the point of the trace. You can confirm that the rest did > run, but they *only* ran at program exit, after the trace. > Basically, the resources are never released when finalizers are > used. This is a big problem in a long-running program. > > If 10000 iterations isn't enough, you can always increase the counter. > > Note that I am using Ruby 1.9.2p136, Linux. Other versions may > behave differently. > > Why the code above? I was noticing in my code that finalizers were > *never* being run under any circumstances. The above is a > stripped-down set of code that acts similarly to mine. > > >From a bit of research online, I've seen comments that say > sometimes values are left in registers, which affects GC. That seems > fair enough in general- but not here. There are 10000 objects here > that aren't being finalized- they're not in all in registers. If > it's the stack, then the first run should also have failed. It's not > the return value, this is nil. It's not the parameter coming in, the > first test would have failed. > > Is it the current scope? I have a feeling that, based on the one > line change I made, that the current scope is somehow being captured > by the finaliser, so that if "a" remains set, the finaliser holds on > to it, and the object is never released. That's just my theory- I > could be wrong. This situation is particularly bad if you want to > set up a finaliser and then immediately return the value (say, as a > result of caching a value)- the finaliser will never be called, > because you can't clear the value before returning it. > > If you've followed me so far, you can probably guess the workaround- > call a separate method to set the finaliser, and clear the parameter > afterward in that call, then return to the caller with a nil return > value. It's annoying, but not too painful. > > What I am incredibly curious about is why this happens in the first > place- and why there doesn't seem too much talk of this specific > problem when using finalizers online. Finalizers failing to work > when used in the current scope without explicitly clearing the > object afterward seems like the sort of problem other people should > be running into more often. > > It's bizarre. I'm wondering what everyone else thinks of it. Have I > missed something? > > Garth >