我在Rails 4.2.6应用程序中有内存泄漏。控制器将一个大的GaragesPresenter
对象分配为一个实例变量,应该在请求完成后对其进行解引用和垃圾回收。但是,我发现这种情况从未发生过。
def show
@garage = GaragesPresenter.new(@garage, view_context)
respond_to do |format|
format.html
end
end
我看到GaragesPresenter
实例正在引用GaragesController
实例,而GaragesController
类正在保存一个实例。在请求完成并且已调用GC.start
之后很久就会这样。 为什么GaragesController
类持有对实例的引用?
我知道这是因为我设置了一个堆转储:
require 'objspace'
...
GC.start
file = File.open("/tmp/dumpfile", 'w')
ObjectSpace.dump_all(output: file)
在结果文件中,我看到以下三个对象:
以下对象是GaragesPresenter,非常大:
{"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}}
GaragesController实例正在保存对上述对象的引用(由于show方法将演示者分配为实例变量,因此预期:
{"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}}
GaragesController类正在举行对上述GaragesController实例的引用,可能是为了防止garabage收集。为什么??
{"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}}
答案 0 :(得分:3)
您需要使用WeakRef
弱引用类,允许引用的对象 垃圾回收。 WeakRef可以与它的对象完全一样使用 引用。
foo = Object.new
foo = WeakRef.new(foo) # Creates a weak reference to orig
ObjectSpace.garbage_collect
p foo.to_s # should raise exception (recycled)
用例是使用两个对象引用的地方。首先是主人,第二是弱者。在使用第一个主链接之前,不会对您的对象进行垃圾回收。在对象中使用主链接(通用变量),它比我们需要引用对象的时间相同或更多。引用对象内部使用弱链接。
这种情况是相应的做法。在其他使用垃圾收集器的语言中,例如在perl中。 C ++库有太多的内存管理策略解决方案。垃圾收集器在使用时无法删除垃圾(对象)。如果对象引用另一个而另一个引用首先这意味着两者都在使用中。所以它不是垃圾 - 它对垃圾收集者的意见很有用#34;但实际上它是垃圾 - 它是内存泄漏。
对象引用图不能有循环或循环。如果我们需要在对象引用图中形成循环或循环的引用,我们需要在每个参考图中使用至少一个准切割弱引用。
答案 1 :(得分:3)
GaragesPresenter
包含对view_context
@garage = GaragesPresenter.new(@garage, view_context)
view_context
返回instance of of a view class,其中包含对self
的引用,这是调用控制器:
# File actionview/lib/action_view/rendering.rb, line 71
def view_context
view_context_class.new(view_renderer, view_assigns, self)
end