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
让我们保存一个副本,sys.modules以便稍后再尝试还原它。因此,这是一个基线4074对象。我们理想地应该以某种方式返回到这一点。
sys.modules
让我们导入一个模块:
import httplib print len(gc.get_objects()) # 7063 objects in memory
我们最多可容纳7K个非垃圾对象。让我们尝试httplib从中删除sys.modules。
httplib
sys.modules.pop('httplib') gc.collect() print len(gc.get_objects()) # 7063 objects in memory
好吧,那没有用。嗯,但是没有参考__main__吗?哦耶:
__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怎么办?
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… Argh!我们回到完全进口httplib。也许如果我们将其替换为虚拟对象?
local_dict
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
Python不支持卸载模块。
但是,除非您的程序随时间加载了无限数量的模块,否则这不是内存泄漏的根源。模块通常在启动时加载一次,仅此而已。您的内存泄漏很可能位于其他地方。
如果您的程序确实确实在一段时间内确实加载了无限数量的模块,那么您应该重新设计程序。;-)