5

我正在玩红宝石终结器,并注意到一些对我来说非常奇怪的行为。我可以将触发代码减少到以下内容:

require "weakref"

class Foo
    def initialize
        ObjectSpace.define_finalizer(self, self.class.finalize)
    end

    def self.finalize
        proc {
            puts "finalizing"
        }
    end
end

Foo.new # does not work
#WeakRef.new(foo) # Using this instead, everything works as expected
sleep 1
ObjectSpace.garbage_collect
puts "... this did not finalize the object"

Foo.new
ObjectSpace.garbage_collect
puts "but this did?"

正如程序所说,在第二次调用 Foo.new 之前没有运行终结器。我尝试在第一次调用垃圾收集器之前增加更多延迟(尽管据我所知,它根本不需要),但这无济于事。

奇怪的是,如果我使用注释掉的行 i,第一个终结器会按照我的预期被调用。在程序退出之前,第二个仍然没有被调用。

谁能解释为什么会这样?我正在运行带有 ruby​​ 1.9.3p194(2012-04-20 修订版 35410)[x86_64-linux] 的 Ubuntu 12.10。我尝试阅读弱引用代码,但据我所知,它所做的只是存储对象 object_id 以便以后检索它。

编辑:我知道在这种情况下手动调用垃圾收集器是没有意义的。我只是想了解这背后的机制。

4

3 回答 3

3

您无法收集您的Foo参考,因为它在您的终结器中被引用!因此,由于终结器本身持有对对象的引用,GC 永远不会收集它,因此永远不会触发终结器。您可以通过对终结器本身使用 Wea​​kRef 来解决此问题:

require "weakref"

class Foo
  class << self
    attr_accessor :objects_finalized

    def finalize
      proc {
        @objects_finalized ||= 0
        @objects_finalized += 1
      }
    end
  end

  def initialize
    ObjectSpace.define_finalizer WeakRef.new(self), self.class.finalize
  end
end

describe Foo do
  it "should be collected" do
    Foo.new
    expect { GC.start }.to change {
      ObjectSpace.each_object(Foo){} }.from(1).to(0)
  end

  it "should be finalized when it is collected" do
    expect { begin; Foo.new; end; GC.start }.to change {
      Foo.objects_finalized }.from(nil).to(1)
  end
end

结果:

% rspec weakref.rb
..

Finished in 0.03322 seconds
2 examples, 0 failures
于 2012-12-29T23:52:25.680 回答
1

我在http://edwinmeyer.com/Release_Integrated_RHG_09_10_2008/chapter05.html上找到了答案(搜索“寄存器和堆栈”)

因为对对象的引用仍然存储在处理器寄存器中,所以垃圾收集器保持安全并假定它仍然存在。

于 2012-12-29T23:29:20.447 回答
0

请记住,与 Objective-C 或 C++ 等语言不同,对象的所有引用一旦消失,它就会消失,Ruby 是一种垃圾收集语言。解释器没有理由为一个对象调用笨重的低效垃圾收集器。当垃圾收集器运行时,所有其他处理都会停止。这是一个很大的性能打击。解释器足够聪明,可以等到大部分垃圾都出来后再收集。

示例:您是否将装有一块垃圾的垃圾袋带到垃圾箱?不,你等到它满了再走。

如果要强制进行 GC 收集,请尝试GC.garbage_collect手动调用收集器。除非你有充分的理由,否则不要在生产中使用它。

于 2012-12-28T04:28:03.200 回答