I'm developing a class that has a finalizer method. In order to test the class, I want to run the garbage collector, then test some states to see if everything worked. However, I can't seem to actually get the garbage collected, so the finalization doesn't happen until the script ends. The following code shows the problem.
class FinalCall
def initialize
ObjectSpace.define_finalizer(self, proc { puts 'finalizing' })
end
end
FinalCall.new
GC.start
puts 'done'
I had expected output like this:
finalizing
done
But I actually get this:
done
finalizing
What am I missing? How do you force GC to finalize everything that's out of scope?
GC.start
is not a guarantee that the garbage collector will run. It is only an advisory that it would be okay for your code if a GC happened at this particular point in time. Requiring the GC to run at a particular point in time would unreasonably constrain implementors. For example, it would be impossible to write a Ruby implementation for the JVM, the CLI, or the ECMAScript or PyPy platform, or to use frameworks like Eclipse OMR, since the GC is not under the control of the implementor.
There is no guarantee when a GC will happen. There is not even a guarantee that a GC will happen at all.
Therefore, there is also no guarantee about when or even if a finalizer will run.
While Jörg is correct, you have an additional problem here: Your finalizer proc creates a closure over self
which increments the reference count and then prevents your object from being collected!
The correct approach is to use a class method which creates a proc which does not close over instances. For example:
class IncorrectFinalCall
def initialize
ObjectSpace.define_finalizer( self, proc { puts 'finalizing IncorrectFinalCall' } )
end
end
class FinalCall
def initialize
ObjectSpace.define_finalizer( self, self.class.finalizer )
end
def self.finalizer
proc { puts 'finalizing FinalCall' }
end
end
10.times do
IncorrectFinalCall.new
FinalCall.new
end
GC.start
puts 'done'
Resulting in:
ruby gc.rb
finalizing FinalCall
finalizing FinalCall
finalizing FinalCall
finalizing FinalCall
finalizing FinalCall
finalizing FinalCall
finalizing FinalCall
finalizing FinalCall
finalizing FinalCall
finalizing FinalCall
done
finalizing IncorrectFinalCall
finalizing IncorrectFinalCall
finalizing IncorrectFinalCall
finalizing IncorrectFinalCall
finalizing IncorrectFinalCall
finalizing IncorrectFinalCall
finalizing IncorrectFinalCall
finalizing IncorrectFinalCall
finalizing IncorrectFinalCall
finalizing IncorrectFinalCall
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With