Ruby中的匿名模块和类垃圾收集

时间:2013-08-26 12:44:10

标签: ruby class module garbage-collection anonymous-class

我想知道为什么以下代码显然不会垃圾收集任何地方不再被引用的匿名模块(不扩展/包含,未命名,包含数组设置为nil)。

如果有人能用相对简单/一般的编程词来澄清发生了什么,我会很感激。是否有一种特殊的红宝石方式来实现这一目标?匿名模块/类无论如何都不能被垃圾收集?或者我只是误导了我得到的记忆统计数据?

注意:我使用的是ruby 1.9.3;不知道ruby 2.x是否会改变任何东西...... 注2:无论模块是否定义了foo方法

,结果都是相同的

提前致谢。

puts("INITIAL OBJECT SPACE OBJECTS : #{ObjectSpace.count_objects}")


i = 100000
ms = []

i.times do
    ms << Module.new do
        def foo()
             puts('foo method called')
        end
    end
end

puts("#{i} MODULES CREATED")
puts("OBJECT SPACE OBJECTS : #{ObjectSpace.count_objects}")

ms = nil
ObjectSpace.garbage_collect

puts("#{i} MODULES GARBAGE COLLECTED")
puts("WAITING TO END PROGRAM")

stop = gets
puts("FINAL OBJECT SPACE OBJECTS : #{ObjectSpace.count_objects}")

我说“显然不是垃圾收集”,因为我的操作系统任务管理器没有显示进程内存使用量的任何减少,并且调用ObjectSpace.count_objects产生以下内容,我读到(错误的是这样?):没有释放模块使用的内存。

  

初始对象空间物体:{:TOTAL =&gt; 14730,:FREE =&gt; 251,:T_OBJECT =&gt; 8,:T_CLASS =&gt; 542,:T_MODULE =&gt; 21,:T_FLOAT =&gt; 7 ,:T_STRING =&gt; 6349,:T_REGEXP =&gt; 24,:T_ARRAY =&gt; 1009,:T_HASH =&gt; 14,:T_BIGNUM =&gt; 3,:T_FILE =&gt; 10,:T_DATA =&gt; 408, :T_MATCH =&gt; 108,:T_COMPLEX =&gt; 1,:T_NODE =&gt; 5956,:T_ICLASS =&gt; 19}

     

创建100000个模块

     

对象空间物体:{:TOTAL =&gt; 311794,:FREE =&gt; 59829,:T_OBJECT =&gt; 6,:T_CLASS =&gt; 542,:T_MODULE =&gt; 100021,:T_FLOAT =&gt; 7, :T_STRING =&gt; 3332,:T_REGEXP =&gt; 22,:T_ARRAY =&gt; 23868,:T_HASH =&gt; 10,:T_BIGNUM =&gt; 3,:T_FILE =&gt; 3,:T_DATA =&gt; 100324,: T_COMPLEX =&gt; 1,:T_NODE =&gt; 23807,:T_ICLASS =&gt; 19}

     

100000模块垃圾收集   等待结束计划

     

最终对象空间物体:{:TOTAL =&gt; 311794,:FREE =&gt; 107155,:T_OBJECT =&gt; 6,:T_CLASS =&gt; 542,:T_MODULE =&gt; 100021,:T_FLOAT =&gt; 7 ,:T_STRING =&gt; 3335,:T_REGEXP =&gt; 22,:T_ARRAY =&gt; 203,:T_HASH =&gt; 10,:T_BIGNUM =&gt; 3,:T_FILE =&gt; 3,:T_DATA =&gt; 100324, :T_COMPLEX =&gt; 1,:T_NODE =&gt; 143,:T_ICLASS =&gt; 19}

2 个答案:

答案 0 :(得分:5)

调用GC.startObjectSpace.garbage_collect 表示将执行垃圾回收。它只是Ruby运行时的一个提示。

在某些平台上,Ruby运行时启动垃圾收集甚至可能,因为垃圾收集器甚至不是Ruby运行时的一部分,例如在JRuby或IronRuby上。 / p>

通常,Ruby运行时将在执行垃圾收集时自行决定。通常,那就是内存耗尽的时候。 100000个模块不 大,所以根本不需要执行GC循环。

此外,即使在GC循环之后,大多数Ruby实现也从不将内存释放回操作系统。

因此,ObjectSpace不缩小的事实并不一定意味着你有内存泄漏。它可能只是意味着Ruby运行时尚未认为有必要运行GC循环。

另请注意,如果您从IRb,Pry,IDE控制台或其他非标准环境运行此代码,那么那些可能会保留其中某些模块。例如,Pry将最后100个命令的结果存储在历史数组中。 (在输入示例程序后,尝试在Pry中评估_out_[5]。)

答案 1 :(得分:1)

您可以查看方法GC#start

puts "INITIAL OBJECT SPACE OBJECTS : #{ObjectSpace.count_objects[:T_MODULE]}"
i = 10
ms = []

i.times do
    ms << Module.new do
        def foo()
             puts('foo method called')
        end
    end
end

puts "#{i} MODULES CREATED" 
puts "OBJECT SPACE OBJECTS : #{ObjectSpace.count_objects[:T_MODULE]}"


p ms
ms = nil
GC.start

puts "#{i} MODULES GARBAGE COLLECTED"
puts "WAITING TO END PROGRAM"
p ms 
puts "FINAL OBJECT SPACE OBJECTS : #{ObjectSpace.count_objects[:T_MODULE]}"

输出:

INITIAL OBJECT SPACE OBJECTS : 21
10 MODULES CREATED
OBJECT SPACE OBJECTS : 31
[#<Module:0xe33a48>, #<Module:0xe338c8>, #<Module:0xe33808>, #<Module:0xe337a8>, #<Module:0xe33610>, 
#<Module:0xe334c0>, #<Module:0xe33328>, #<Module:0xe33250>, #<Module:0xe33118>, #<Module:0xe33088>]
10 MODULES GARBAGE COLLECTED
WAITING TO END PROGRAM
nil
FINAL OBJECT SPACE OBJECTS : 23

所以你可以看到垃圾收集后我得到的最终数为23而不是21,这完全由 @JörgWMittag 解释。