I have a memory leak in a Rails 4.2.6 application. A controller allocates a large GaragesPresenter
object as an instance variable, which should be de-referenced and garbage collected after the request completes. However, I see that this never happens.
def show
@garage = GaragesPresenter.new(@garage, view_context)
respond_to do |format|
format.html
end
end
I see that a reference to the GaragesPresenter
instance is being held by the GaragesController
instance, and an instance to that is being held by the GaragesController
class. This is true long after the request has completed and GC.start
has been called. Why is the GaragesController
class holding a reference to the instance?
I know this because I set up a heap dump with:
require 'objspace'
...
GC.start
file = File.open("/tmp/dumpfile", 'w')
ObjectSpace.dump_all(output: file)
And in the resulting file I see the following three objects:
The following object is a GaragesPresenter, which is very large:
{"address":"0x7fd077217e20", "type":"OBJECT", "class":"0x7fd074a04618", "ivars":7, "references":["0x7fd0772bf940", "0x7fd077711480", "0x7fd077748188", "0x7fd077772898", "0x7fd07720c778", "0x7fd0771ef8d0", "0x7fd0771ef8d0"], "file":"/Users/dyoung/workspace/commutyble/site-app/app/controllers/garages_controller.rb", "line":19, "method":"new", "generation":35, "memsize":56, "flags":{"wb_protected":true, "old":true, "marked":true}}
A reference to the above object is being held by a GaragesController instance (expected, as the show method allocates the presenter as an instance variable):
{"address":"0x7fd0727559f0", "type":"OBJECT", "class":"0x7fd0727865a0", "ivars":22, "references":["0x7fd0727558b0", "0x7fd072755888", "0x7fd072755838", "0x7fd0732400e0", "0x7fd072754a50", "0x7fd0734c5658", "0x7fd07704e878", "0x7fd0732ab020", "0x7fd072785ee8", "0x7fd077217e20", "0x7fd0771ffe10", "0x7fd07720cde0", "0x7fd0732a82d0"], "file":"/Users/dyoung/.rvm/gems/ruby-2.1.0/gems/actionpack-4.2.6/lib/action_controller/metal.rb", "line":237, "method":"new", "generation":35, "memsize":176, "flags":{"wb_protected":true, "old":true, "marked":true}}
A reference to the above GaragesController instance is being held by the GaragesController class, presumably preventing garabage collection. Why??
{"address":"0x7fd0727865a0", "type":"CLASS", "class":"0x7fd0726a7260", "name":"GaragesController", "references":["0x7fd0727559f0", "0x7fd0726a72b0"], "file":"/Users/dyoung/.rvm/gems/ruby-2.1.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb", "line":435, "method":"instance_exec", "generation":35, "memsize":672, "flags":{"wb_protected":true, "old":true, "marked":true}}