相互引用的类的内存泄漏

时间:2021-10-04 14:02:33

For the curious: It turns out my memory leak had nothing to do with what I put in the sample here. I thought I had the issue nailed down to some sample code, but my sample code had different issues. I did end up finding my real issue though, and that's here: Ruby Symbol#to_proc leaks references in 1.9.2-p180?

对于好奇的人来说:我的内存泄漏与我在这里放入的样本无关。我认为我已经把这个问题固定到一些示例代码中,但是我的示例代码有不同的问题。但是我最终发现了我真正的问题,那就是:Ruby符号#to_proc泄漏了1.9.2-p180中的引用?

I have two ruby classes (Generator and Member, in this example) where Generator serves as a factory (in a loose definition of the term) of Member objects, and each Member holds a reference to the Generator that constructed it.

我有两个ruby类(在本例中是Generator和Member),其中Generator作为成员对象的工厂(在术语的松散定义中),每个成员都持有对构建它的生成器的引用。

Code:

代码:

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

Using IRB, I'd expect that if I simply call I simply call Member.get(Generator.new), but not actually assign the result to anything, both the reference to the newly-constructed Generator object and the newly-constructed Member object should have zero references laying around. So the garbage collector should collect both objects. But it only collects the Members, leaving the Generator sitting around:

使用IRB,我希望如果我简单地调用Member.get(Generator.new),但实际上并没有将结果赋值给任何东西,那么对新构造的生成器对象和新构造的成员对象的引用都应该是零引用。因此垃圾收集器应该收集这两个对象。但它只收集成员,而让生成器无所事事:

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, as I understand it, returns a list of references to a given class still on ruby's heap.)

(ObjectSpace。根据我的理解,each_object返回仍然在ruby堆上的给定类的引用列表。

Why is there still a reference to the Generator object sitting around? I haven't saved it to a variable in any way, so there shouldn't be anything referencing it anymore. The Member object got collected, so its instance variable that references the Generator class shouldn't be preventing it from getting collected.

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

I'm not just curious, either. We have a Sinatra app that has a similar class structure, and the equivalent Generator class stores a huge cache of Member objects, several hundred megs per request, and it never gets collected. Ruby runs out of memory and the app server has to restart every dozen or so requests.

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

1 个解决方案

#1


6  

When you call

当你打电话

Member.get(Generator.new)

you set the class instance variable @generator for the Member class:

为成员类设置类实例变量@generator:

@generator = generator

And by calling the initial line Member.get(Generator.new), there is nothing that would create a Member, you simply create an instance of Generator, which is then assigned to the class instance variable.

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

That leaves:

这使得:

  • One instance of Generator assigned to Member class instance variable @generator
  • 分配给成员类实例变量@generator的一个生成器实例。
  • No instance of Member was ever created
  • 从来没有创建过成员实例
  • The class instance variable @generator of Member will not get collected because the class Member will not get collected
  • 成员的类实例变量@generator不会被收集,因为类成员不会被收集

-> The results you receive are perfectly normal, nothing wrong with Ruby's Garbage Collection.

->你收到的结果是完全正常的,Ruby的垃圾收集没有任何问题。

#1


6  

When you call

当你打电话

Member.get(Generator.new)

you set the class instance variable @generator for the Member class:

为成员类设置类实例变量@generator:

@generator = generator

And by calling the initial line Member.get(Generator.new), there is nothing that would create a Member, you simply create an instance of Generator, which is then assigned to the class instance variable.

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

That leaves:

这使得:

  • One instance of Generator assigned to Member class instance variable @generator
  • 分配给成员类实例变量@generator的一个生成器实例。
  • No instance of Member was ever created
  • 从来没有创建过成员实例
  • The class instance variable @generator of Member will not get collected because the class Member will not get collected
  • 成员的类实例变量@generator不会被收集,因为类成员不会被收集

-> The results you receive are perfectly normal, nothing wrong with Ruby's Garbage Collection.

->你收到的结果是完全正常的,Ruby的垃圾收集没有任何问题。