views:

72

answers:

1

Hi gurus, I've found a weird effect when trying to track down a memory leak in a Rails app. Can anyone explain what's going on here?

Save this script as a plain Ruby script (Rails not necessary):

class Fnord
    def to_s
        'fnord'
    end
end

def test
    f = Fnord.new
end

test

GC.start
sleep 2

ObjectSpace.each_object do |o|
    puts o if o.is_a? Fnord
end

When I run this via

ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

I get the following:

bash $ ruby var_test
fnord

Although the variable f is out of scope, there are no other references to the single Fnord object, and I've garbage collected, the object still seems to exist. Is this a nefarious memory leak of some sort, or am I completely missing something about Ruby?

Further, if I change the test method to this:

def test
    f = Fnord.new
    f = nil
end

I get no output. But surely this should not change the semantics here?

Many thanks!

+2  A: 

I think the difference between your two versions is not about the value of f, but about the fact that in your first version test will return the new Fnord object while in the second version test will return nil.

As a matter of fact the object will be garbage collected if any value comes between Fnord.new and GC.start. For example simply adding a line 42 between the call to test and the call to GC.start will cause the object to be collected.

I'm not sure why this is the case, but I suspect that the ruby interpreter holds on to the value of the last evaluated expression for some reason.

sepp2k
Yep, the last expression's value is always referenced by the `_` variable.
Chuck
Of course -- thanks.
Andrew Clegg
@Chuck: Only in irb, though. If I put `23+19` and then `puts _` in an rb file and run it, I get "undefined local variable or method `_' for main:Object (NameError)".
sepp2k