Ruby Symbol#to_proc泄漏了1.9.2-p180中的引用?

好的,这是我第二次尝试使用我的Sinatra应用调试内存问题。 我相信这次我把它固定成简单的示例代码。

似乎当我通过.map(&:some_method)过滤数组时,它会导致该数组中的项目无法收集垃圾。 运行等效的.map{|x| x.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) 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虫吗? 我会尝试更多版本的ruby来确定,但这似乎是一个明显的问题。 谁知道我做错了什么?

编辑:

我在1.8.7-p352中尝试了这个,它没有问题。 但是,1.9.3-preview1仍有问题。 是错误报告还是我做错了什么?

Edit2:格式化(为什么在每行之前放置四个空格会产生语法高亮,而

标签不会?) 

因为a.map(&:foo)应该与a.map{|x| x.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) pb a = b = nil GC.start p ObjectSpace.each_object(C) {} 

打印0