$search
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)