python-python內存泄露跟蹤

最近被python的內存使用搞得比較的鬱悶,記錄在案。

 

內存泄漏的經典定義是曾經使用過一次的內存,現在卻沒有,但還沒有被回收。使用純Python代碼幾乎不可能。但正如Antoine指出的那樣,即使您不需要保留所有數據,您也可以通過允許數據結構無限制地增長來輕鬆地消耗所有內存。

1 將值存儲在類或全局範圍而不是實例範圍中,而不是實現它。

比如下面的這個代碼:

class Money(object):
    name = ''
    symbols = []   # This is the dangerous line here

    def set_name(self, name):
        self.name = name

    def add_symbol(self, symbol):
        self.symbols.append(symbol)


m = Money()
m.set_name('Dollar')
m.add_symbol('$')

那麼正確的寫法應該是如何呢?

class Money(object):
    self.name = ''
    self.symbols = []   # This is the dangerous line here

    def set_name(self, name):
        self.name = name

    def add_symbol(self, symbol):
        self.symbols.append(symbol)

2 sys.exc_info()帶來的循環引用

問題代碼如下:

while game.running():
    try:
        key_press = handle_input()
    except SomeException:
        etype, evalue, tb = sys.exc_info()
        # Do something with tb like inspecting or printing the traceback

這裏面我們可能認爲tb是一個臨時變量,但是實際上,tb包含了handle_input運行的上下文信息。如果game一直在執行中,那麼tb依然不會被釋放,哪怕是下一次執行handle_input。

3 在類中自己實現__del__方法

class ClientConnection(...):
    def __del__(self):
        if self.socket is not None:
            self.socket.close()
            self.socket = None
現在這個工作正常,你可能會認爲它是操作系統資源的良好管理者,以確保套接字被“處置”。

但是,如果ClientConnection保留引用說明,用戶和用戶保留對連接的引用,您可能會想要說清理時,讓用戶取消引用連接。這實際上是一個缺陷:循環GC不知道正確的操作順序,也無法清理它。

對此的解決方案是確保你通過調用某種類型的關閉來斷開事件,但是將該方法命名爲__del__以外的其他方法。

4 非正常使用C庫

 

在Python中,您相信垃圾收集器會丟棄您不使用的內容。但是,如果使用包裝C庫的C擴展,則大多數時候您負責確保明確關閉或取消分配資源。大多數情況下都記錄了這一點,但是習慣於不必進行此顯式取消分配的python程序員可能會丟棄句柄(如從函數或其他任何內容返回)到該庫而不知道資源被保留。

 

 

 

 

 

【參考文獻】

【1】https://stackoverflow.com/questions/2017381/is-it-possible-to-have-an-actual-memory-leak-in-python-because-of-your-code

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章