在 Python 中卸载模块

2024-03-18

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


Python 不支持卸载模块。

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

在不太可能的情况下,您的程序确实随着时间的推移加载了无限数量的模块,您可能应该重新设计您的程序。 ;-)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Python 中卸载模块 的相关文章

随机推荐