gc exposes the underlying memory management mechanism of Python, the automatic garbage collector. The module includes functions for controlling how the collector operates and to examine the objects known to the system, either pending collection or stuck in reference cycles and unable to be freed.

Tracing References


In [1]:
import gc
import pprint
class Graph:

    def __init__(self, name):
        self.name = name
        self.next = None

    def set_next(self, next):
        print('Linking nodes {}.next = {}'.format(self, next))
        self.next = next

    def __repr__(self):
        return '{}({})'.format(
            self.__class__.__name__, self.name)


# Construct a graph cycle
one = Graph('one')
two = Graph('two')
three = Graph('three')
one.set_next(two)
two.set_next(three)
three.set_next(one)

print()
print('three refers to:')
for r in gc.get_referents(three):
    pprint.pprint(r)


Linking nodes Graph(one).next = Graph(two)
Linking nodes Graph(two).next = Graph(three)
Linking nodes Graph(three).next = Graph(one)

three refers to:
{'name': 'three', 'next': Graph(one)}
<class '__main__.Graph'>

In [2]:
import gc
import pprint
import queue


class Graph:

    def __init__(self, name):
        self.name = name
        self.next = None

    def set_next(self, next):
        print('Linking nodes {}.next = {}'.format(self, next))
        self.next = next

    def __repr__(self):
        return '{}({})'.format(
            self.__class__.__name__, self.name)


# Construct a graph cycle
one = Graph('one')
two = Graph('two')
three = Graph('three')
one.set_next(two)
two.set_next(three)
three.set_next(one)

print()

seen = set()
to_process = queue.Queue()

# Start with an empty object chain and Graph three.
to_process.put(([], three))

# Look for cycles, building the object chain for each object
# found in the queue so the full cycle can be printed at the
# end.
while not to_process.empty():
    chain, next = to_process.get()
    chain = chain[:]
    chain.append(next)
    print('Examining:', repr(next))
    seen.add(id(next))
    for r in gc.get_referents(next):
        if isinstance(r, str) or isinstance(r, type):
            # Ignore strings and classes
            pass
        elif id(r) in seen:
            print()
            print('Found a cycle to {}:'.format(r))
            for i, link in enumerate(chain):
                print('  {}: '.format(i), end=' ')
                pprint.pprint(link)
        else:
            to_process.put((chain, r))


Linking nodes Graph(one).next = Graph(two)
Linking nodes Graph(two).next = Graph(three)
Linking nodes Graph(three).next = Graph(one)

Examining: Graph(three)
Examining: {'name': 'three', 'next': Graph(one)}
Examining: Graph(one)
Examining: {'name': 'one', 'next': Graph(two)}
Examining: Graph(two)
Examining: {'name': 'two', 'next': Graph(three)}

Found a cycle to Graph(three):
  0:  Graph(three)
  1:  {'name': 'three', 'next': Graph(one)}
  2:  Graph(one)
  3:  {'name': 'one', 'next': Graph(two)}
  4:  Graph(two)
  5:  {'name': 'two', 'next': Graph(three)}

Forcing Garbage Collection


In [3]:
import gc
import pprint


class Graph:

    def __init__(self, name):
        self.name = name
        self.next = None

    def set_next(self, next):
        print('Linking nodes {}.next = {}'.format(self, next))
        self.next = next

    def __repr__(self):
        return '{}({})'.format(
            self.__class__.__name__, self.name)


# Construct a graph cycle
one = Graph('one')
two = Graph('two')
three = Graph('three')
one.set_next(two)
two.set_next(three)
three.set_next(one)

# Remove references to the graph nodes in this module's namespace
one = two = three = None

# Show the effect of garbage collection
for i in range(2):
    print('\nCollecting {} ...'.format(i))
    n = gc.collect()
    print('Unreachable objects:', n)
    print('Remaining Garbage:', end=' ')
    pprint.pprint(gc.garbage)


Linking nodes Graph(one).next = Graph(two)
Linking nodes Graph(two).next = Graph(three)
Linking nodes Graph(three).next = Graph(one)

Collecting 0 ...
Unreachable objects: 562
Remaining Garbage: []

Collecting 1 ...
Unreachable objects: 0
Remaining Garbage: []

Collection Thresholds and Generations


In [4]:
import gc

print(gc.get_threshold())


(700, 10, 10)

Debugging


In [5]:
import gc

gc.set_debug(gc.DEBUG_STATS)

gc.collect()
print('Exiting')


Exiting
gc: collecting generation 2...
gc: objects in each generation: 182 0 47042
gc: done, 0.0146s elapsed

In [6]:
import gc

flags = (gc.DEBUG_COLLECTABLE |
         gc.DEBUG_UNCOLLECTABLE |
         gc.DEBUG_SAVEALL
         )

gc.set_debug(flags)


class Graph:

    def __init__(self, name):
        self.name = name
        self.next = None

    def set_next(self, next):
        self.next = next

    def __repr__(self):
        return '{}({})'.format(
            self.__class__.__name__, self.name)


class CleanupGraph(Graph):

    def __del__(self):
        print('{}.__del__()'.format(self))


# Construct a graph cycle
one = Graph('one')
two = Graph('two')
one.set_next(two)
two.set_next(one)

# Construct another node that stands on its own
three = CleanupGraph('three')

# Construct a graph cycle with a finalizer
four = CleanupGraph('four')
five = CleanupGraph('five')
four.set_next(five)
five.set_next(four)

# Remove references to the graph nodes in this module's namespace
one = two = three = four = five = None

# Force a sweep
print('Collecting')
gc.collect()
print('Done')

# Report on what was left
for o in gc.garbage:
    if isinstance(o, Graph):
        print('Retained: {} 0x{:x}'.format(o, id(o)))

# Reset the debug flags before exiting to avoid dumping a lot
# of extra information and making the example output more
# confusing.
gc.set_debug(0)


CleanupGraph(three).__del__()
Collecting
CleanupGraph(four).__del__()
CleanupGraph(five).__del__()
Done
Retained: Graph(one) 0x1051fc8d0
Retained: Graph(two) 0x1051cdf98
Retained: CleanupGraph(four) 0x1051fc630
Retained: CleanupGraph(five) 0x1051fc518
gc: collectable <frame 0x105145e10>
gc: collectable <frame 0x1051639a8>
gc: collectable <list 0x1050b4308>
gc: collectable <frame 0x7fcc8d8285b8>
gc: collectable <cell 0x1051917c8>
gc: collectable <tuple 0x1051dcc88>
gc: collectable <function 0x1051c6950>
gc: collectable <frame 0x7fcc8d82fbc8>
gc: collectable <frame 0x1051d1a20>
gc: collectable <frame 0x7fcc8d830248>
gc: collectable <frame 0x7fcc8d828258>
gc: collectable <tuple 0x1051d0138>
gc: collectable <tuple 0x1050c6188>
gc: collectable <traceback 0x1050c6c48>
gc: collectable <traceback 0x1050c6cc8>
gc: collectable <SyntaxError 0x1051c60d0>
gc: collectable <frame 0x7fcc8d82a2f8>
gc: collectable <tuple 0x1051e4f48>
gc: collectable <tuple 0x1050c6d48>
gc: collectable <traceback 0x1050c6c08>
gc: collectable <traceback 0x1050c6b88>
gc: collectable <SyntaxError 0x1051c6598>
gc: collectable <frame 0x7fcc8d907778>
gc: collectable <cell 0x105191978>
gc: collectable <tuple 0x104e965f8>
gc: collectable <function 0x1051c68c8>
gc: collectable <frame 0x7fcc8d9069b8>
gc: collectable <frame 0x1051e2d68>
gc: collectable <frame 0x7fcc8b75eac8>
gc: collectable <frame 0x1051e8630>
gc: collectable <tuple 0x1051e41d8>
gc: collectable <tuple 0x1050c6748>
gc: collectable <traceback 0x1050c6f88>
gc: collectable <traceback 0x1050c6bc8>
gc: collectable <SyntaxError 0x1051c69d8>
gc: collectable <frame 0x1051e8438>
gc: collectable <tuple 0x1051e4ef8>
gc: collectable <tuple 0x1050c6d08>
gc: collectable <traceback 0x1050c8f48>
gc: collectable <traceback 0x1050c8f08>
gc: collectable <SyntaxError 0x1051c6a60>
gc: collectable <frame 0x1051ed9d0>
gc: collectable <cell 0x105191828>
gc: collectable <tuple 0x1051f1a20>
gc: collectable <function 0x1051c62f0>
gc: collectable <frame 0x7fcc8b75ee28>
gc: collectable <frame 0x105163d68>
gc: collectable <frame 0x7fcc8b75fa48>
gc: collectable <frame 0x1051e8240>
gc: collectable <tuple 0x1051e4db8>
gc: collectable <tuple 0x1050c6708>
gc: collectable <traceback 0x1050c8dc8>
gc: collectable <traceback 0x1050c8e48>
gc: collectable <SyntaxError 0x1051c6bf8>
gc: collectable <frame 0x1051e8048>
gc: collectable <tuple 0x1051e4958>
gc: collectable <tuple 0x1050ba988>
gc: collectable <traceback 0x1050c8d88>
gc: collectable <traceback 0x1050c8d08>
gc: collectable <SyntaxError 0x1051c6d08>
gc: collectable <frame 0x1051ed600>
gc: collectable <cell 0x105191b28>
gc: collectable <tuple 0x1051f1d68>
gc: collectable <function 0x1051c6e18>
gc: collectable <frame 0x7fcc8b75fda8>
gc: collectable <frame 0x1051d2048>
gc: collectable <frame 0x7fcc8b75ffe8>
gc: collectable <frame 0x1051e8828>
gc: collectable <tuple 0x1051e4408>
gc: collectable <tuple 0x1050cce88>
gc: collectable <traceback 0x1050c8608>
gc: collectable <traceback 0x1050c8cc8>
gc: collectable <SyntaxError 0x1051c6ea0>
gc: collectable <frame 0x1051d5c18>
gc: collectable <tuple 0x1051e45e8>
gc: collectable <tuple 0x1050c6608>
gc: collectable <traceback 0x1050c8648>
gc: collectable <traceback 0x1050c85c8>
gc: collectable <SyntaxError 0x1051c6f28>
gc: collectable <frame 0x1051edbb8>
gc: collectable <cell 0x105191c18>
gc: collectable <tuple 0x1051f19b0>
gc: collectable <function 0x1051c66a8>
gc: collectable <frame 0x7fcc8d908518>
gc: collectable <frame 0x1051d2228>
gc: collectable <frame 0x7fcc8d908758>
gc: collectable <frame 0x1051d5828>
gc: collectable <tuple 0x1051e4638>
gc: collectable <tuple 0x1050c6308>
gc: collectable <traceback 0x1050c8348>
gc: collectable <traceback 0x1050c8448>
gc: collectable <SyntaxError 0x1051c6730>
gc: collectable <frame 0x1051d5630>
gc: collectable <tuple 0x1051e4778>
gc: collectable <tuple 0x1050c6388>
gc: collectable <traceback 0x1050c87c8>
gc: collectable <traceback 0x1050c8488>
gc: collectable <SyntaxError 0x1051c67b8>
gc: collectable <frame 0x1051ed418>
gc: collectable <cell 0x105191f18>
gc: collectable <tuple 0x1051f1e80>
gc: collectable <function 0x1051c6840>
gc: collectable <frame 0x7fcc8d908ab8>
gc: collectable <frame 0x1051d2b88>
gc: collectable <frame 0x7fcc8d908cf8>
gc: collectable <frame 0x1051d5e10>
gc: collectable <tuple 0x1051e4c78>
gc: collectable <tuple 0x1050c2088>
gc: collectable <traceback 0x1050c8748>
gc: collectable <traceback 0x1050c80c8>
gc: collectable <SyntaxError 0x1051c6488>
gc: collectable <frame 0x1051d5048>
gc: collectable <tuple 0x1051e4c28>
gc: collectable <tuple 0x1050c8788>
gc: collectable <traceback 0x1050c8188>
gc: collectable <traceback 0x1050c8a48>
gc: collectable <SyntaxError 0x1051c6400>
gc: collectable <frame 0x1051edda0>
gc: collectable <cell 0x105191888>
gc: collectable <tuple 0x104e967b8>
gc: collectable <function 0x1051c6378>
gc: collectable <frame 0x7fcc8d82b7f8>
gc: collectable <frame 0x1051d27c8>
gc: collectable <frame 0x7fcc8d8287f8>
gc: collectable <frame 0x1051d1630>
gc: collectable <tuple 0x1051e4908>
gc: collectable <tuple 0x1050c6448>
gc: collectable <traceback 0x1050c89c8>
gc: collectable <traceback 0x1050c8988>
gc: collectable <SyntaxError 0x1051c6c80>
gc: collectable <frame 0x1051d1438>
gc: collectable <tuple 0x1051e4728>
gc: collectable <tuple 0x1050c6e48>
gc: collectable <traceback 0x1050c8288>
gc: collectable <traceback 0x1050c8848>
gc: collectable <SyntaxError 0x1051e7ae8>
gc: collectable <frame 0x1051ed230>
gc: collectable <cell 0x105191df8>
gc: collectable <tuple 0x1051f1748>
gc: collectable <function 0x1051e7a60>
gc: collectable <frame 0x7fcc8d82fe08>
gc: collectable <frame 0x1051d2408>
gc: collectable <frame 0x7fcc8d8278c8>
gc: collectable <frame 0x1051d1240>
gc: collectable <tuple 0x1051e46d8>
gc: collectable <tuple 0x1050c0148>
gc: collectable <traceback 0x1050c4a48>
gc: collectable <traceback 0x1050c4c08>
gc: collectable <SyntaxError 0x1051e7950>
gc: collectable <frame 0x1051d1048>
gc: collectable <tuple 0x1051e4688>
gc: collectable <tuple 0x1050c6208>
gc: collectable <traceback 0x1050c4b88>
gc: collectable <traceback 0x1050c4ac8>
gc: collectable <SyntaxError 0x1051e7b70>
gc: collectable <frame 0x1051ed7e8>
gc: collectable <cell 0x105191af8>
gc: collectable <tuple 0x1051f1e48>
gc: collectable <function 0x104e9cae8>
gc: collectable <frame 0x7fcc8d827c28>
gc: collectable <frame 0x1051e9048>
gc: collectable <frame 0x7fcc8d82d308>
gc: collectable <frame 0x1051d1c18>
gc: collectable <tuple 0x1051eb638>
gc: collectable <tuple 0x1050c8908>
gc: collectable <traceback 0x1050b7f48>
gc: collectable <traceback 0x1050b9848>
gc: collectable <SyntaxError 0x1051b2048>
gc: collectable <frame 0x7fcc8b6de478>
gc: collectable <tuple 0x1051eb188>
gc: collectable <tuple 0x1050c8248>
gc: collectable <traceback 0x1050b98c8>
gc: collectable <traceback 0x1050c4408>
gc: collectable <SyntaxError 0x1051e7bf8>
gc: collectable <frame 0x1051c9600>
gc: collectable <cell 0x105191ee8>
gc: collectable <tuple 0x1051f1860>
gc: collectable <function 0x1051e7d08>
gc: collectable <frame 0x7fcc8d909058>
gc: collectable <frame 0x1051e9228>
gc: collectable <frame 0x7fcc8d909298>
gc: collectable <frame 0x1051d1828>
gc: collectable <tuple 0x1051eb7c8>
gc: collectable <tuple 0x1050c5608>
gc: collectable <traceback 0x1050c44c8>
gc: collectable <traceback 0x1050c4908>
gc: collectable <SyntaxError 0x1051e7f28>
gc: collectable <frame 0x1051d1e10>
gc: collectable <tuple 0x1051eb098>
gc: collectable <tuple 0x1050c6d88>
gc: collectable <traceback 0x1050c4308>
gc: collectable <traceback 0x1050c4988>
gc: collectable <SyntaxError 0x1051e7e18>
gc: collectable <type 0x7fcc8d828d08>
gc: collectable <tuple 0x1050c2f48>
gc: collectable <dict 0x1051f65e8>
gc: collectable <function 0x1051c6d90>
gc: collectable <function 0x1051c6b70>
gc: collectable <function 0x1051c6ae8>
gc: collectable <getset_descriptor 0x1051f6a68>
gc: collectable <getset_descriptor 0x1051f6af8>
gc: collectable <Graph 0x1051fc8d0>
gc: collectable <Graph 0x1051cdf98>
gc: collectable <dict 0x105208318>
gc: collectable <dict 0x1051ce750>
gc: collectable <CleanupGraph 0x1051fc630>
gc: collectable <CleanupGraph 0x1051fc518>
gc: collectable <dict 0x1051ce828>
gc: collectable <dict 0x1051ce5e8>