当最后一个引用超出范围时,为什么不删除我的Ruby对象?

时间:2010-04-04 19:06:22

标签: ruby memory-leaks scoping

在尝试跟踪Rails应用程序中的内存泄漏时,我发现了一个奇怪的效果。谁能解释一下这里发生了什么?

将此脚本保存为纯Ruby脚本(不需要Rails):

class Fnord
    def to_s
        'fnord'
    end
end

def test
    f = Fnord.new
end

test

GC.start
sleep 2

ObjectSpace.each_object do |o|
    puts o if o.is_a? Fnord
end

当我通过

运行时
ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

我得到以下内容:

bash $ ruby var_test
fnord

虽然变量f超出了范围,但是没有其他对单个Fnord对象的引用,而且我已经收集了垃圾,该对象似乎仍然存在。这是某种邪恶的内存泄漏,还是我完全错过了一些关于Ruby的东西?

此外,如果我将测试方法更改为:

def test
    f = Fnord.new
    f = nil
end

我没有输出。但是这肯定不会改变这里的语义吗?

非常感谢!

1 个答案:

答案 0 :(得分:2)

我认为您的两个版本之间的区别不在于f的值,而在于您的第一个版本test将在第二个版本test中返回新的Fnord对象这一事实返回nil

事实上,如果Fnord.newGC.start之间存在任何值,则会对对象进行垃圾回收。例如,只需在调用42和调用test之间添加一行GC.start即可收集该对象。

我不确定为什么会这样,但我怀疑ruby解释器出于某种原因保留了最后一个评估表达式的值。