TL/DR:
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
更新 关于这个问题,我已经联系了 Python 开发人员,实际上完全是“未来五年”的 无法卸载模块
请接受 Python 确实不支持在2.x 中为严重的、基本的、不可克服的技术问题卸载模块。
在我最近寻找我的应用程序中的一个内存泄漏的过程中,我把范围缩小到了模块,也就是说我无法使用 收垃圾一个卸载的模块。使用下面列出的 任何方法卸载一个模块会在内存中留下数千个对象。换句话说,我不能卸载 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
万岁,下降了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
去死吧,去死吧!
import httplib
for attr in dir(httplib):
setattr(httplib, attr, None)
gc.collect()
print len(gc.get_objects()) # 6749 objects in memory
好吧,在所有的尝试之后,最好的是 + 2675(接近 + 50%)从起点... 这只是从一个模块... 这甚至没有任何大的内部..。
好了,说真的,我的错误在哪里? 我如何卸载一个模块并清除它的所有内容? 还是巨蟒的模块是一个巨大的内存泄漏?
完整源代码以更简单的形式复制: http://gist.github.com/450606