4

这是这个问题的一个想法:在创建对象时,增加一个类变量。当对象被收集时,减少它。如您所见,finalizer 被调用,@@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
4

2 回答 2

6

它可以工作,但在最终确定中有循环引用。您的终结器取决于应收集的对象的绑定。请参阅此解决方案

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
于 2013-05-28T17:25:17.437 回答
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 实例。

于 2013-05-28T14:52:11.180 回答