出于好奇:原来我的内存泄漏与我在此处放入样本的内容无关。我以为我已将问题确定为一些示例代码,但我的示例代码有不同的问题。不过,我确实最终找到了我的真正的问题,那就在这里:Ruby Symbol#to_proc leaks references in 1.9.2-p180?
我有两个 ruby 类(Generator
和 Member
,在本例中),其中 Generator 用作 Member 对象的工厂(在术语的松散定义中),每个成员都持有对构建它的生成器的引用。
代码:
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)
,但实际上不会将结果分配给任何东西,包括对 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 内存不足,应用服务器必须每十几个请求重新启动一次。
最佳答案
当你打电话时
Member.get(Generator.new)
您为成员类设置了类实例变量 @generator
:
@generator = generator
并且通过调用初始行 Member.get(Generator.new),没有任何东西可以创建 Member,您只需创建一个 Generator 实例,然后将其分配给类实例变量。
剩下:
- 一个Generator实例分配给Member类实例变量@generator
- 从未创建过成员的实例
- Member 的类实例变量@generator 不会被回收,因为类Member 不会被回收
-> 你收到的结果是完全正常的,Ruby 的垃圾收集没有问题。
关于ruby - 相互引用的类的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7237277/