Ruby强制垃圾回收未按预期工作

3
在以下代码中:
class ExampleClass
  def initialize
    ObjectSpace.define_finalizer(self, proc{puts 'dead'})
  end
end

ex = ExampleClass.new
ex = nil

GC.start

while true
  # the while loop is to prevent the program from terminate
  # if the program does terminate, the finalizer gets called in the end like expected
end

这里的终结器从未被调用,也没有输出。我本以为垃圾回收器会收集已取消引用的ex。为什么GC.start不能强制回收ex并立即导致终结器被调用?

如果我使用control+c关闭你的代码,或者将while true end替换为exit,我会看到dead打印。 我正在使用Ruby 2.5.0-dev。 顺便问一下,你在哪个平台上? - max pleaner
我正在使用Ruby 2.4.0在Eclipse上。 - aoiee
哦,而且终结器在没有GC.start的情况下可以工作吗? - max pleaner
我想知道为什么当我调用GC.start时,dead没有正确打印。我在那里放了一个while循环来显示程序不会终止。 - aoiee
1个回答

2
我相信当你创建一个新的Procproc 只是调用 Kernel 中的 Proc.new)时,这意味着它保存了对当前上下文的引用,因此无法被垃圾回收器解除引用。你应该在类方法中创建 proc,以便上下文变为类而不是你想要销毁的实例。
class ExampleClass
  def initialize
    ObjectSpace.define_finalizer(self, self.class.finalize)
  end

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

end


ex = ExampleClass.new
# needed to do something with the object as well, not sure why,
# but it won't work without this line either
puts "object id = #{ex.object_id}"
ex = nil

GC.start
while true
end

这将输出:
object id = 70223915005060
dead
^Cexample.rb:20:in `<main>': Interrupt

非常感谢您的解释!我尝试了一下,甚至不需要额外的 puts "object id = #{ex.object_id}" 也可以运行。 - aoiee
1
啊,是的,我不记得以前需要它,但如果没有它,它就无法运行,所以我猜测是我的 Ruby 实现有问题。但是,实际上你可能会为了某些目的使用对象,而不仅仅是实例化一些东西,以便我们可以运行终结器。 - Simple Lime

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接