而當Object的reference count減至0的時候,Python的GC會找時間把這些Object清除掉。
對Python而言,memory leak產生的可能性有兩種
- Circular reference
- Referece在global的變數或是module上
其實有些tool可以找到這種reference的關係,這邊介紹的是 objgraph - 官網,視覺化的Reference結果圖,讓人一目瞭然。
可以在下載後安裝
pip install objgraph
或是直接將壓縮檔內的objgraph.py解壓放在執行檔旁,因為objgraph就這麼一個檔案!
不過,為了將objgraph解析後的狀態轉成圖檔,還需要安裝另一個tool - graphviz,這個是跟python無關的tool,只是objgraph輸出一個config檔,透過subprocess執行graphviz去讀取這個config檔,然後輸出最後關係圖的圖檔。接著可以透過關係圖檔找到應該解除reference link的地方,再一一破解,應該就可以解開memory leak了。
以下示範較常用的show_backrefs()
還有其他的API可直接參照objgraph.py裡
Reference:
以下示範較常用的show_backrefs()
還有其他的API可直接參照objgraph.py裡
Example: Value object reference 在 Container 裡
class Value(object): def __init__(self, v): object.__init__(self) self.v = v def get(self): return self.v def set(self, v): self.v = v class Container(object): def __init__(self): object.__init__(self) self.children = [] def get(self, idx): return self.children[idx] def pop(self): c = self.children.pop() return c def push(self, c): return self.children.append(c) if __name__== '__main__': c1 = Container() c1.push(Value(100)) import objgraph objgraph.show_backrefs([c.get(0)], filename='test.png')輸出結果圖:
Example 2: 2個Container同時reference在同一個Value object
if __name__== '__main__': c1 = Container() c1.push(Value(100)) c2 = Container() c2.push(c1.get(0)) import objgraph objgraph.show_backrefs([c.get(0)], filename='test.png')輸出結果圖:
Example 3: circular reference
if __name__== '__main__': c1 = Container() v = Value(c1) c1.push(v) #circular reference import objgraph objgraph.show_backrefs([c1.get(0)], max_depth=5, filename='test.png')輸出結果圖:
Reference:
- objgraph - official site
- graphviz - offcial site
- PyPI - objgraph
沒有留言:
張貼留言