#!/usr/bin/env python # encoding: utf-8 # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # """Show the objects with references to a given object. """ #end_pymotw_header import gc import pprint import Queue class Graph(object): def __init__(self, name): self.name = name self.next = None def set_next(self, next): print 'Linking nodes %s.next = %s' % (self, next) self.next = next def __repr__(self): return '%s(%s)' % (self.__class__.__name__, self.name) def __del__(self): print '%s.__del__()' % self # Construct two graph cycles 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 # Collecting now keeps the objects as uncollectable print print 'Collecting...' n = gc.collect() print 'Unreachable objects:', n print 'Remaining Garbage:', pprint.pprint(gc.garbage) REFERRERS_TO_IGNORE = [ locals(), globals(), gc.garbage ] def find_referring_graphs(obj): print 'Looking for references to %s' % repr(obj) referrers = (r for r in gc.get_referrers(obj) if r not in REFERRERS_TO_IGNORE) for ref in referrers: if isinstance(ref, Graph): # A graph node yield ref elif isinstance(ref, dict): # An instance or other namespace dictionary for parent in find_referring_graphs(ref): yield parent # Look for objects that refer to the objects that remain in # gc.garbage. print print 'Clearing referrers:' for obj in gc.garbage: for ref in find_referring_graphs(obj): ref.set_next(None) del ref # remove local reference so the node can be deleted del obj # remove local reference so the node can be deleted # Clear references held by gc.garbage print print 'Clearing gc.garbage:' del gc.garbage[:] # Everything should have been freed this time print print 'Collecting...' n = gc.collect() print 'Unreachable objects:', n print 'Remaining Garbage:', pprint.pprint(gc.garbage)