最近被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程序員可能會丟棄句柄(如從函數或其他任何內容返回)到該庫而不知道資源被保留。
【參考文獻】