类相互引用的内存泄漏

时间:2011-08-29 23:46:51

标签: ruby garbage-collection

对于好奇的:事实证明我的内存泄漏与我在此处放入的示例无关。我认为我的问题已经解决了一些示例代码,但我的示例代码有不同的问题。我最终找到了真正的问题,而且就在这里:Ruby Symbol#to_proc leaks references in 1.9.2-p180?

我有两个ruby类(在此示例中为GeneratorMember),其中Generator充当成员对象的工厂(在术语的松散定义中),并且每个成员都拥有一个引用到构建它的发电机。

代码:

class Generator
  def new_member
    Member.new
  end
end

class Member
  attr_reader :generator

  def self.get(generator)
    @generator = generator
    puts "Provided generator: #{generator}"
    generator.new_member
  end
end

使用IRB,我希望如果我只是简单地调用我只是调用Member.get(Generator.new),但实际上没有将结果分配给任何东西,那么对新构造的Generator对象的引用和新对象都是构造的Member对象应该有零参考。所以垃圾收集器应该收集这两个对象。但它只收集会员,让发电机坐在那里:

ruby-1.9.2-p180 :001 > Member.get(Generator.new)
Provided generator: #<Generator:0x007fcf398015c8>
 => #<Member:0x007fcf39801550>
ruby-1.9.2-p180 :006 > GC.start
 => nil 
ruby-1.9.2-p180 :007 > ObjectSpace.each_object(Member){|m| puts m}
 => 0 
ruby-1.9.2-p180 :008 > ObjectSpace.each_object(Generator){|g| puts g}
#<Generator:0x007fcf398015c8>
 => 1

ObjectSpace.each_object,据我所知,它返回一个仍然在ruby堆上的给定类的引用列表。)

为什么仍然存在对坐在的Generator对象的引用?我没有以任何方式将它保存到变量中,所以不应再有任何引用它的东西了。收集了Member对象,因此引用Generator类的实例变量不应该阻止它被收集。

我也不仅仅是好奇。我们有一个具有类似类结构的Sinatra应用程序,等效的Generator类存储了一个巨大的Member对象缓存,每个请求有几百兆,并且它永远不会被收集。 Ruby内存不足,应用服务器必须重新启动每十几个请求。

1 个答案:

答案 0 :(得分:7)

致电时

Member.get(Generator.new)

为Member类设置类实例变量 @generator

@generator = generator

通过调用初始行Member.get(Generator.new),没有什么可以创建一个Member,你只需创建一个Generator实例,然后将其分配给类实例变量。

离开:

  • 分配给成员类实例变量@generator
  • 的Generator的一个实例
  • 没有创建会员的实例
  • 将不会收集成员的类实例变量@generator,因为不会收集类成员

- &GT;你收到的结果是完全正常的,Ruby的垃圾收集没有错。