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开发人员联系,实际上,“在未来五年内”不可能完全卸载模块。 (请参阅链接)
请接受,在2.x中,Python确实不支持针对严重,根本,不可克服的技术问题的卸载模块。
在我最近一次寻找应用程序内存泄漏的过程中,我将其范围缩小到模块,即我无法垃圾收集已卸载的模块。 使用下面列出的任何方法卸载模块都会在内存中保留数千个对象。 换句话说-我无法在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
让我们保存一个__main__的副本,以便稍后尝试恢复它。因此,这是一个基线4074对象。 我们理想地应该以某种方式返回到这一点。
让我们导入一个模块:
import httplib
print len(gc.get_objects()) # 7063 objects in memory
我们最多可容纳7K个非垃圾对象。让我们尝试从local_dict中删除__main__。
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多个原始对象。让我们尝试从副本中还原__main__。
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
如果我们将__main__放在local_dict内部,该怎么办?
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]