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
UPDATE我已经就这个问题联系了Python开发人员,确实是这样无法卸载模块 http://bugs.python.org/issue9072完全是“未来五年”。 (见链接)
请接受,Python 在 2.x 中确实不支持卸载模块以解决严重的、基本的、无法克服的技术问题。
在我最近在我的应用程序中寻找 memleak 的过程中,我将其范围缩小到了模块,即我无法垃圾收集一个卸载的模块。使用any下面列出的卸载模块的方法会在内存中留下数千个对象。换句话说 - 我无法在 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 个非垃圾对象。
我们来尝试删除httplib
from sys.modules
.
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?
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%)...那只是来自一个模块...里面甚至没有任何大东西...
好吧,现在说真的,我的错误在哪里?
如何卸载模块并清除其所有内容?
或者Python的模块是一个巨大的内存泄漏吗?
完整源代码更易于复制:http://gist.github.com/450606 http://gist.github.com/450606