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