TL/DR:卸載模塊在Python
import gc, sys
print len(gc.get_objects()) # 4073 objects in memory
# Attempt to unload the module
import httplib
del sys.modules["httplib"]
httplib = None
gc.collect()
print len(gc.get_objects()) # 6745 objects in memory
UPDATE 我已經聯繫Python開發者對這個問題,事實上它是 「在未來五年」 not going to be possible to unload a module完全。 (請參閱鏈接)
請接受Python確實不支持在2.x中爲卸載嚴重的,基本的,難以克服的技術問題卸載模塊。
在我最近的追捕我的應用程序一個memleak,我已經將範圍縮小到模塊,即我不能垃圾收集空載模塊。使用任何下面列出的方法卸載模塊會在內存中留下數千個對象。換句話說 - 我不能在Python中卸載模塊...
問題的其餘部分是試圖以某種方式垃圾收集模塊。
讓我們試試:
import gc
import sys
sm = sys.modules.copy() # httplib, which we'll try to unload isn't yet
# in sys.modules, so, this isn't the source of problem
print len(gc.get_objects()) # 4074 objects in memory
讓我們節省的sys.modules
副本嘗試後恢復它。 所以,這是一個基線4074個對象。理想情況下,我們應該以某種方式回到這一點
讓我們導入模塊:
import httplib
print len(gc.get_objects()) # 7063 objects in memory
我們高達7K非垃圾對象。 讓我們嘗試從sys.modules
刪除httplib
。
sys.modules.pop('httplib')
gc.collect()
print len(gc.get_objects()) # 7063 objects in memory
那麼,這並沒有奏效。嗯,但是__main__
沒有參考嗎?哦,是的:是的:
del httplib
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Hooray,下降300個對象。儘管如此,沒有雪茄,這是超過4000個原始物體的方式。 讓我們試着從複製中恢復sys.modules
。
sys.modules = sm
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
嗯,很好,是沒有意義的,沒有任何變化.. 也許如果我們消滅了全局...
globals().clear()
import gC# we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
本地人?
locals().clear()
import gC# we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
什麼..如果我們imported
的exec
內的模塊?
local_dict = {}
exec 'import httplib' in local_dict
del local_dict
gc.collect()
print len(gc.get_objects()) # back to 7063 objects in memory
現在,這是不公平的,它導入到__main__
,爲什麼呢?它應該從來沒有離開local_dict
......唉!我們回到完全導入httplib
。 也許如果我們用虛擬對象替換它?
from types import ModuleType
import sys
print len(gc.get_objects()) # 7064 objects in memory
血腥..... !!
sys.modules['httplib'] = ModuleType('httplib')
print len(gc.get_objects()) # 7066 objects in memory
Die modules,die !!
import httplib
for attr in dir(httplib):
setattr(httplib, attr, None)
gc.collect()
print len(gc.get_objects()) # 6749 objects in memory
好了,所有的嘗試後,最好是2675(將近+ 50%),從起點......這只是從一個模塊......這甚至都沒有什麼大的內...
好吧,現在認真,我的錯誤在哪裏? 如何卸載模塊並清除所有內容?或者Python的模塊是一個巨大的內存泄漏?在簡單的
完整的源代碼複製形式:http://gist.github.com/450606
是的,它確實加載了合理無限數量的模塊 - 它是一個Web應用服務器,接受它自己的源代碼的新版本並重新加載它(這是非常標準的Web任務)。漏洞源於舊代碼仍然存在於內存中,即使被替換,即使無法訪問... – 2010-06-23 21:52:49
Python確實支持卸載模塊。它們是垃圾收集的,就像Python中的其他對象一樣。 – 2010-06-23 22:56:24
@Slava:你可能想看看'mod_python'的源代碼,它有自己的導入器,用於處理重裝模塊而不產生內存泄漏。那裏可能有一些你可以使用的代碼。 – 2010-06-23 23:00:33