ruby - 相互引用的类的内存泄漏

标签 ruby garbage-collection

出于好奇:原来我的内存泄漏与我在此处放入样本的内容无关。我以为我已将问题确定为一些示例代码,但我的示例代码有不同的问题。不过,我确实最终找到了我的真正的问题,那就在这里:Ruby Symbol#to_proc leaks references in 1.9.2-p180?

我有两个 ruby​​ 类(GeneratorMember,在本例中),其中 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/

相关文章:

ruby - 如何在 YAML 文件中创建动态键名

ruby - 是否可以在 Gemfile 之外要求文件?

ruby-on-rails - form_tag 路由不正确

ruby-on-rails - 如何根据连接表按频率获取 ActiveRecord 对象列表

java - System.gc() 什么时候做某事?

java - JVM 故障转储中的标准并行 GC 被称为什么?

java - 当这个新的Thread()在Android中被GC时?

ruby-on-rails - 将具有 UTC 时间的变量转换为秒整数 (Ruby)

java - 何时以及如何将 java 类加载器标记为垃圾收集?

c# - 方法地址会被垃圾收集器移动吗?