How to count existing instances of a class in ruby?

前端 未结 2 576
孤城傲影
孤城傲影 2020-12-18 10:17

Here\'s an idea from this question: Upon object creation, increment a class variable. When object gets collected, decrement it. As you can observe, finalizer is called, and

相关标签:
2条回答
  • 2020-12-18 10:41

    Finalization is not happening when you think it should in the code you provided.

    For example, if you change that one line to:

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

    Then notice how it does nothing (even if I sit there and wait a while) until I kill 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
    

    So the first assumption may be that GC was not invoked. But, lets look at it using 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
    

    So, it looks like the GC is getting invoked when you ask it to, but it is not finalizing the Foo instance until irb exit.

    0 讨论(0)
  • 2020-12-18 10:53

    It can work, but there's circular reference in finalization. Your finalizer depends on the binding of an object that should be collected. See 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
    
    0 讨论(0)
提交回复
热议问题