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
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.
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