Ok, this is my second attempt at debugging the memory issues with my Sinatra app. I believe I have it nailed down into simple sample code this time.
It seems when I filter an array through .map(&:some_method)
, it causes the items in that array to not get garbage collected. Running the equivalent .map{|x| x.some_method}
is totally fine.
Demonstration: Given a simple sample class:
class C
def foo
"foo"
end
end
If I run the following in IRB, it gets collected normally:
ruby-1.9.2-p180 :001 > a = 10.times.map{C.new}
=> [...]
ruby-1.9.2-p180 :002 > b = a.map{|x| x.foo}
=> ["foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo"]
ruby-1.9.2-p180 :003 > ObjectSpace.each_object(C){}
=> 10
ruby-1.9.2-p180 :004 > a = nil
=> nil
ruby-1.9.2-p180 :005 > b = nil
=> nil
ruby-1.9.2-p180 :006 > GC.start
=> nil
ruby-1.9.2-p180 :007 > ObjectSpace.each_object(C){}
=> 0
So no references to C exist anymore. Good. But substituting map{|x| x.foo} with map(&:foo)
(which is advertised as equivalent), it doesn't get collected:
ruby-1.9.2-p180 :001 > a = 10.times.map{C.new}
=> [...]
ruby-1.9.2-p180 :002 > b = a.map(&:foo)
=> ["foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo"]
ruby-1.9.2-p180 :003 > ObjectSpace.each_object(C){}
=> 10
ruby-1.9.2-p180 :004 > a = nil
=> nil
ruby-1.9.2-p180 :005 > b = nil
=> nil
ruby-1.9.2-p180 :006 > GC.start
=> nil
ruby-1.9.2-p180 :007 > ObjectSpace.each_object(C){}
=> 10
ruby-1.9.2-p180 :008 >
Is this a ruby bug? I'll try in more versions of ruby to be sure but this seems like an obvious issue. Anyone know what I'm doing wrong?
Edit:
I've tried this in 1.8.7-p352 and it doesn't have the issue. 1.9.3-preview1 does however still have the issue. Is a bug report in order or am I doing something wrong?
Edit2: formatting (why does putting four spaces before each line produce syntax highlighting while <pre>
tags don't?)
As
a.map(&:foo)
should be the exact equivalent toa.map{|x| x.foo}
, it seems like you really hit a bug in the Ruby code here. It cannot hurt to file a bug report on (http://redmine.ruby-lang.org/), the worst that can happen is that its being ignored. You can decrease the chances of that by providing a patch for the issue.EDIT: I threw on my IRB and tried your code. I can reproduce the issue you describe on
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
. However, explicitely callingto_proc
on the symbol does not suffer from the same problem:It seems we are facing an issue with the implicit
Symbol -> Proc
conversion here. Maybe I will try to dive a bit into the Ruby source later. If so, I will keep you updated.EDIT 2:
Simple workaround for the problem:
prints
0
.