gcdebug.py
Go to the documentation of this file.
00001 import inspect, gc
00002 from collections import deque
00003 import yapgvb
00004 import os.path
00005 
00006 def follow_back(a, n):
00007     """Handy function for seeing why an object is still live by walking
00008     back through its referrers."""
00009     def print_elem(e):
00010         print repr(e)[0:200]
00011         try:
00012             print e.f_code.co_filename, e.f_lineno
00013             #print e.f_locals
00014             #print dir(e)
00015         except:
00016             pass
00017     print
00018     print "Follow back:"
00019     print_elem(a)
00020     for i in range(n):
00021         r = gc.get_referrers(a)
00022         r.remove(inspect.currentframe())
00023         print
00024         print len(r)
00025         for e in r:
00026             print_elem(e)
00027         a = r[0]
00028 
00029 def compare_before_after(before, after):
00030     """Handy function to compare live objects before and after some
00031     operation, to debug why memory is leaking."""
00032     beforeids = set(id(e) for e in before)
00033     afterids = set(id(e) for e in after)
00034     delta = afterids - beforeids - set([id(before)])
00035     for e in after:
00036         if id(e) in delta:
00037             print e
00038 
00039 def dump_back_reference_graph(obj, maxdepth):
00040     obj = obj()
00041     if obj is None:
00042         print "Weakref was freed."
00043         return
00044 
00045     curframe = inspect.currentframe()
00046     
00047     todo = deque([(obj, 0)])
00048     strings = {}
00049     objects = {}
00050     depths = {}
00051     edges = []
00052     skipped = set()
00053 
00054     def element_string(e):
00055         if type(e) == list:
00056             return "list"
00057         if type(e) == type(curframe):
00058             return "frame: %s:%i"%(os.path.basename(e.f_code.co_filename), e.f_lineno)
00059         if type(e) == dict:
00060             return "\n".join(["%10s : %20s"%(str(k)[0:10], str(v)[0:10]) for k, v in e.iteritems()][0:10])
00061         
00062         #if type(e) == tuple:
00063         #    return "tuple"
00064         return str(e)[0:40]
00065 
00066     def list_str_bounded(l, join_str, max_indices, max_elem):
00067         l = [str(e)[0:max_elem] for e in l]
00068         if len(l) > max_indices:
00069             l = l[0:max_indices]
00070             l.append('...')
00071         return join_str.join(l)
00072 
00073     def edge_string(e1, e2):
00074         if type(e1) == list:
00075             return list_str_bounded([i for i in range(len(e1)) if e1[i] == e2], ", ", 10, 10)
00076 
00077         if type(e1) == dict:
00078             keys = [str(k)[0:20] for (k,v) in e1.iteritems() if e2 == v]
00079             return list_str_bounded([k for (k,v) in e1.iteritems() if e2 == v], "\n", 10, 20)
00080         
00081         return list_str_bounded([a for a in dir(e1) if e1.__getattribute__(a) == e2], "\n", 10, 20)
00082 
00083     def dont_trace(e):
00084         if type(e) == type(inspect):
00085             return True
00086         return False
00087     
00088     while todo:
00089         e, d = todo.popleft()
00090         ide = id(e)
00091         if ide in strings or d > maxdepth:
00092             continue
00093         strings[ide] = element_string(e)
00094         depths[ide] = d
00095         objects[ide] = e
00096         if dont_trace(e):
00097             skipped.add(ide)
00098             continue
00099         d += 1
00100         refs = gc.get_referrers(e)
00101         refs.remove(curframe)
00102         for r in list(refs):
00103             if r in todo or r == objects:
00104                 refs.remove(r)
00105         todo.extend((r, d) for r in refs)
00106         edges.extend((id(r), ide) for r in refs)
00107         del refs
00108            
00109     print "Found %i nodes and %i edges"%(len(strings), len(edges))
00110     #for s in strings.values():
00111     #    print s
00112 
00113     graph = yapgvb.Digraph('Referrers')
00114     nodes = {}
00115     colors = ["red", "orange", "yellow", "green", "blue", "purple", "black"]
00116     ncol = len(colors)
00117     for (ids, s) in strings.items():
00118         nodes[ids] = graph.add_node(str(ids), label=s,
00119                 color=colors[depths[ids]%ncol])
00120         if ids in skipped:
00121             nodes[ids].shape = 'box'
00122         if depths[ids] == maxdepth:
00123             nodes[ids].shape = 'parallelogram'
00124     
00125     for (id1, id2) in edges:
00126         if id1 in nodes and id2 in nodes:
00127             edge = nodes[id1] >> nodes[id2]
00128             s = edge_string(objects[id1], objects[id2])
00129             if s:
00130                 edge.label = s
00131 
00132     graph.root = str(id(obj))
00133     #graph.layout(yapgvb.engines.twopi)
00134     graph.layout(yapgvb.engines.dot)
00135     graph.render('gcgraph.ps')
00136     del objects
00137 
00138 if __name__ == "__main__":
00139     import weakref
00140     l1 = []
00141     l2 = [l1]
00142     #l2.append(l2)
00143     l3 = [l1, l2]
00144     l4 = [l3]
00145     l1.append(l4)
00146     class Foo:
00147         pass
00148     f = Foo()
00149     f.l = l1
00150     l4.append(f)
00151     wr = weakref.ref(f)
00152     del l1
00153     del l2
00154     del l3
00155     del l4
00156     del f
00157     dump_back_reference_graph(wr, 10)


multi_interface_roam
Author(s): Blaise Gassend
autogenerated on Wed Sep 16 2015 04:38:26