【问题标题】:Ruby Symbol#to_proc leaks references in 1.9.2-p180?Ruby Symbol#to_proc 泄漏 1.9.2-p180 中的引用?
【发布时间】:2011-08-31 20:53:12
【问题描述】:

好的,这是我第二次尝试调试我的 Sinatra 应用程序的内存问题。我相信这次我已经把它写成了简单的示例代码。

似乎当我通过.map(&:some_method) 过滤一个数组时,它会导致该数组中的项目没有被垃圾收集。运行等效的.map{|x| x.some_method} 完全没问题。

演示:给定一个简单的示例类:

class C
  def foo
    "foo"
  end
end

如果我在 IRB 中运行以下命令,它会被正常收集:

ruby-1.9.2-p180 :001 > a = 10.times.map{C.new}
 => [...]
ruby-1.9.2-p180 :002 > b = a.map{|x| x.foo}
 => ["foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo"]
ruby-1.9.2-p180 :003 > ObjectSpace.each_object(C){}
 => 10
ruby-1.9.2-p180 :004 > a = nil
 => nil
ruby-1.9.2-p180 :005 > b = nil
 => nil
ruby-1.9.2-p180 :006 > GC.start
 => nil
ruby-1.9.2-p180 :007 > ObjectSpace.each_object(C){}
 => 0

因此不再存在对 C 的引用。好的。但是替换map{|x| x.foo} with map(&:foo)(被宣传为等效),它不会被收集:

ruby-1.9.2-p180 :001 > a = 10.times.map{C.new}
 => [...]
ruby-1.9.2-p180 :002 > b = a.map(&:foo)
 => ["foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo"]
ruby-1.9.2-p180 :003 > ObjectSpace.each_object(C){}
 => 10
ruby-1.9.2-p180 :004 > a = nil
 => nil
ruby-1.9.2-p180 :005 > b = nil
 => nil
ruby-1.9.2-p180 :006 > GC.start
 => nil
ruby-1.9.2-p180 :007 > ObjectSpace.each_object(C){}
 => 10
ruby-1.9.2-p180 :008 >

这是一个红宝石错误吗?我会尝试更多版本的 ruby​​ 来确定,但这似乎是一个明显的问题。有谁知道我做错了什么?

编辑:

我已经在 1.8.7-p352 中尝试过,但没有问题。 1.9.3-preview1 确实但是仍然有问题。是按顺序报告错误还是我做错了什么?

Edit2:格式化(为什么在每行前放置四个空格会产生语法高亮,而 <pre> 标记不会?)

【问题讨论】:

    标签: ruby memory-leaks


    【解决方案1】:

    由于a.map(&:foo) 应该与a.map{|x| x.foo} 完全等价,因此您似乎在此处的 Ruby 代码中遇到了错误。在 (http://redmine.ruby-lang.org/) 上提交错误报告并没有什么坏处,可能发生的最糟糕的情况是它被忽略了。您可以通过为问题提供补丁来减少发生这种情况的可能性。

    编辑:我投入了 IRB 并尝试了您的代码。我可以重现您在ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux] 上描述的问题。但是,在符号上显式调用 to_proc 不会遇到同样的问题:

    irb(main):001:0> class C; def foo; end; end
    => nil
    irb(main):002:0> a = 10.times.map { C.new }
    => [...]
    irb(main):004:0> b = a.map(&:foo.to_proc)
    => [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
    irb(main):005:0> ObjectSpace.each_object(C){}
    => 10
    irb(main):006:0> a = b = nil
    => nil
    irb(main):007:0> GC.start
    => nil
    irb(main):008:0> ObjectSpace.each_object(C){}
    => 0
    

    似乎我们在这里遇到了隐式Symbol -> Proc 转换的问题。也许我稍后会尝试深入研究 Ruby 源代码。如果是这样,我会及时通知您。

    编辑 2:

    问题的简单解决方法:

    class Symbol
      def to_proc
        lambda { |x| x.send(self) }
      end
    end
    
    class C
      def foo; "foo"; end
    end
    
    a = 10.times.map { C.new }
    b = a.map(&:foo)
    p b
    a = b = nil
    GC.start
    p ObjectSpace.each_object(C) {}
    

    打印0

    【讨论】:

    • 我会尝试发送错误报告,但我无法在 Ruby redmine 上设置帐户。我会等到稍后,以防他们的登录系统出现问题。
    • 我正在使用 Google Mail,它会将他们的确认邮件标记为垃圾邮件。也许你应该检查你的垃圾邮件文件夹:D
    • 好电话!我不知道他们甚至发送了一封确认邮件。无论如何,错误 #5261:redmine.ruby-lang.org/issues/5261
    猜你喜欢
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 2011-03-13
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    • 2017-05-08
    • 1970-01-01
    相关资源
    最近更新 更多