一尘不染

用Python卸载模块

python

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对象。我们理想地应该以某种方式返回到这一点。

让我们导入一个模块:

import httplib
print len(gc.get_objects()) # 7063 objects in memory

我们最多可容纳7K个非垃圾对象。让我们尝试httplib从中删除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().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
Argh!我们回到完全进口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


阅读 147

收藏
2020-12-20

共1个答案

一尘不染

Python不支持卸载模块。

但是,除非您的程序随时间加载了无限数量的模块,否则这不是内存泄漏的根源。模块通常在启动时加载一次,仅此而已。您的内存泄漏很可能位于其他地方。

如果您的程序确实确实在一段时间内确实加载了无限数量的模块,那么您应该重新设计程序。;-)

2020-12-20