I'm trying to understand the internals of the CPython garbage collector, specifically when the destructor is called. So far, the behavior is intuitive, but the following case trips me up:
I thought this would only happen if the garbage collector was enabled. Can someone explain why this happens? Is there a way to defer calling the destructor?
import gc
import unittest
_destroyed = False
class MyClass(object):
def __del__(self):
global _destroyed
_destroyed = True
class GarbageCollectionTest(unittest.TestCase):
def testExplicitGarbageCollection(self):
gc.disable()
ref = MyClass()
ref = None
# The next test fails.
# The object is automatically destroyed even with the collector turned off.
self.assertFalse(_destroyed)
gc.collect()
self.assertTrue(_destroyed)
if __name__=='__main__':
unittest.main()
Disclaimer: this code is not meant for production -- I've already noted that this is very implementation-specific and does not work on Jython.
Python has both reference counting garbage collection and cyclic garbage collection, and it's the latter that the gc
module controls. Reference counting can't be disabled, and hence still happens when the cyclic garbage collector is switched off.
Since there are no references left to your object after ref = None
, its __del__
method is called as a result of its reference count going to zero.
There's a clue in the documentation: "Since the collector supplements the reference counting already used in Python..." (my emphasis).
You can stop the first assertion from firing by making the object refer to itself, so that its reference count doesn't go to zero, for instance by giving it this constructor:
def __init__(self):
self.myself = self
But if you do that, the second assertion will fire. That's because garbage cycles with __del__
methods don't get collected - see the documentation for gc.garbage.