如何计算ruby中类的现有实例?

时间:2013-05-28 14:40:47

标签: ruby garbage-collection

这是来自this question的想法:在创建对象时,增加一个类变量。收集对象后,减少它。如您所见,调用终结器,@@no_foo递减。但是当我稍后查询它时,减量就消失了。似乎价值只会上升,永不下降(如果我创建两个对象,它将显示2)。我错过了一些明显的东西吗?

class Foo
  @@no_foo = 0

  def initialize
    puts 'creating object'
    @@no_foo += 1
    ObjectSpace.define_finalizer(self, proc { self.delete })
  end

  def delete
    puts 'deleting object'
    @@no_foo # => 1
    @@no_foo -= 1
    @@no_foo # => 0
  end

  def self.no_foo
    @@no_foo # => 0, 1
  end
end

Foo.no_foo # => 0
f = Foo.new
f = nil

GC.start
Foo.no_foo # => 1

# >> creating object
# >> deleting object

2 个答案:

答案 0 :(得分:6)

它可以工作,但在最终确定中有循环引用。你的终结器取决于应该收集的对象的绑定。请参阅this solution

class Foo
  @@no_foo = 0

  def initialize
    @@no_foo += 1
    ObjectSpace.define_finalizer(self, Foo.method(:delete))
  end

  def self.delete id # also this argument seems to be necessary
    @@no_foo -= 1
  end

  def self.no_foo
    @@no_foo
  end
end

Foo.no_foo # => 0
1000.times{Foo.new}
Foo.no_foo # => 1000

GC.start
Foo.no_foo # => 0

答案 1 :(得分:3)

当您认为应该在您提供的代码中时,不会发生最终确定。

例如,如果您将该行更改为:

ObjectSpace.define_finalizer(self, proc do; puts "self is type #{self.class.name} and equals #{self.inspect}"; self.delete; end)

然后注意它是怎么做的(即使我坐在那里等待一段时间)直到我杀了irb:

... (entered class definition from above with that define_finalizer)
1.9.3-p392 :021 > Foo.no_foo # => 0
 => 0 
1.9.3-p392 :022 > f = Foo.new
creating object
 => #<Foo:0x007fb5730f3e00> 
1.9.3-p392 :023 > f = nil
 => nil 
1.9.3-p392 :024 > 
1.9.3-p392 :025 > GC.start
 => nil 
1.9.3-p392 :026 > Foo.no_foo # => 1
 => 1 
1.9.3-p392 :027 > ^D
self is type Foo and equals #<Foo:0x007fb5730f3e00>
deleting object

所以第一个假设可能是没有调用GC。但是,让我们使用GC::Profiler

来查看它
1.9.3p392 :001 > GC::Profiler.enable
... (entered class definition from above)
1.9.3p392 :022 > puts GC::Profiler.result
GC 17 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC Time(ms)
 => nil 
1.9.3p392 :023 > Foo.no_foo # => 0
 => 0 
1.9.3p392 :024 > f = Foo.new
creating object
 => #<Foo:0x007fe2fc806808> 
1.9.3p392 :025 > puts GC::Profiler.result
GC 17 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC Time(ms)
 => nil 
1.9.3p392 :026 > f = nil
 => nil 
1.9.3p392 :027 > puts GC::Profiler.result
GC 17 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC Time(ms)
 => nil 
1.9.3p392 :028 > GC.start
 => nil 
1.9.3p392 :029 > puts GC::Profiler.result
GC 18 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC Time(ms)
    1               0.161               997280              2257680                56442         3.96199999999999352696
 => nil 
1.9.3p392 :030 > Foo.no_foo # => 1
 => 1 
1.9.3p392 :031 > ^D
deleting object

因此,当你提出要求时,看起来GC会被调用,但是在irb退出之前它还没有完成Foo实例。