Ruby类对象垃圾回收

25

Ruby中所有的类都是Class类的对象。既然类也是对象,那么Ruby虚拟机是否对类对象采用相同的垃圾回收策略呢?是什么决定了一个类对象是否安全地进行垃圾回收?

4个回答

15

另一个更具体的例子,类似于 Andrew Cholakian 的回答,是使用 ObjectSpace。例如:

2.1.1 :001 > ObjectSpace.count_objects[:T_CLASS]
 => 884 
2.1.1 :002 > 10000.times { Class.new }
 => 10000 
2.1.1 :003 > ObjectSpace.count_objects[:T_CLASS]
 => 20884 
2.1.1 :004 > GC.start
 => nil 
2.1.1 :005 > ObjectSpace.count_objects[:T_CLASS]
 => 884 
这表明匿名类(未保存在任何常量中或被这些类的任何实例使用)确实会被垃圾回收。

1

我测试了一下,答案是看起来是这样的。

irb(main):001:0> x = [] #Memory Usage = 12MB
=> []
irb(main):002:0> 120000.times {x << Class.new} #Memory usage now at 41 MB
=> 120000
irb(main):013:0> x = []
=> []
irb(main):011:0> GC.start() #Memory usage now at 13MB
=> nil

0

我不知道答案是什么,但你能不能通过实验找到答案呢?看看pickaxe。我相信这只是一个非常幼稚的测试,有人可以做得更好,但你明白我的意思:

puts "program start"    
include ObjectSpace

class SfbdTest
   def initialize(a)
      @a = a
   end
end
define_finalizer(SfbdTest, proc{|id| puts "GC on class"} )

puts "creating instance"
x = SfbdTest.new(1)
define_finalizer(x, proc{|id| puts "GC on instance"} )

puts "zombie-ing instance"
x = nil

puts "forcing GC"
GC.start()

puts "program end"

生成:

sfbd@thing:~$ ruby -w test.rb
program start
creating instance
zombie-ing instance
forcing GC
program end
GC on instance
GC on class
sfbd@thing:~$ 

看起来需要一个线程,但不幸的是我应该在工作,抱歉...


0

当没有任何东西链接到该对象时,就可以安全地将其删除。至于垃圾回收何时运行,那超出了我的知识范畴。


1
这通常是正确的,但类可以被视为一种特殊情况。例如,如果一个类没有实例,并且没有被任何其他类子类化,它就没有“链接”(正如你所说),但它真的安全吗?如果有人打算在以后从中构建一个实例,怎么办?我认为对于类来说,情况并不像你所描述的那样清晰 :) - horseyguy
@banister:这正是我想指出的特殊情况之一,其中GC可能需要以特殊方式处理类对象。 - Vaibhav Gumashta
1
很好。 一个类只不过是一个常量,不是吗? 而且你无法摆脱一个常量,因为它是环境中的变量(即使它是IRB的“主”对象或运行时),直到环境完成。“class String”与“String = Class.new”是相同的东西。 - Trevoke
只要有一个常量指向这个类,那么肯定存在链接。但是你可以通过remove_const来删除常量,并且可以创建从未被常量引用的类,即没有名称的类。所以如果这种情况确实存在,而且没有子类或实例,也没有变量或常量指向该类,则不存在链接。在这种情况下,除了使用ObjectSpace(也适用于可回收对象)之外,无法以任何方式访问或实例化该类。 - sepp2k
如果我知道的话,我就会发布一个答案。;-) 我只是说他们在理论上可以被垃圾回收。 - sepp2k
显示剩余4条评论

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