Sla*_*a V 53 python memory-leaks
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
Run Code Online (Sandbox Code Playgroud)
更新 我已经与Python开发人员联系了这个问题,事实上,"未来五年" 无法完全卸载模块.(见链接)
请接受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
Run Code Online (Sandbox Code Playgroud)
我们保存一份副本,sys.modules
以便稍后尝试恢复.所以,这是一个基线4074个对象.理想情况下,我们应该以某种方式回归.
我们导入一个模块:
import httplib
print len(gc.get_objects()) # 7063 objects in memory
Run Code Online (Sandbox Code Playgroud)
我们有7K非垃圾对象.我们试着httplib
从中删除sys.modules
.
sys.modules.pop('httplib')
gc.collect()
print len(gc.get_objects()) # 7063 objects in memory
Run Code Online (Sandbox Code Playgroud)
好吧,那没用.嗯,但是没有参考__main__
?哦耶:
del httplib
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Run Code Online (Sandbox Code Playgroud)
万岁,300件物品.不过,没有雪茄,超过4000个原始物品.我们试着sys.modules
从副本中恢复.
sys.modules = sm
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Run Code Online (Sandbox Code Playgroud)
嗯,这是毫无意义的,没有变化..也许如果我们消灭全局...
globals().clear()
import gc # we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Run Code Online (Sandbox Code Playgroud)
当地人?
locals().clear()
import gc # we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Run Code Online (Sandbox Code Playgroud)
什么..如果我们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
Run Code Online (Sandbox Code Playgroud)
现在,这不公平,它导入了__main__
,为什么?它应该永远不会离开local_dict
......唉!我们回到完全进口httplib
.也许如果我们用虚拟对象替换它?
from types import ModuleType
import sys
print len(gc.get_objects()) # 7064 objects in memory
Run Code Online (Sandbox Code Playgroud)
血腥.....!!
sys.modules['httplib'] = ModuleType('httplib')
print len(gc.get_objects()) # 7066 objects in memory
Run Code Online (Sandbox Code Playgroud)
模具模块,模具!!
import httplib
for attr in dir(httplib):
setattr(httplib, attr, None)
gc.collect()
print len(gc.get_objects()) # 6749 objects in memory
Run Code Online (Sandbox Code Playgroud)
好吧,经过所有的尝试,最好的是从起点开始的+2675(差不多+ 50%)...这只是来自一个模块......那里面甚至都没有什么大的......
好的,现在认真的,我的错误在哪里?如何卸载模块并清除所有内容?或者Python的模块是一个巨大的内存泄漏?
完整的来源,更简单的复制形式:http://gist.github.com/450606
Dan*_*ach 16
Python不支持卸载模块.
但是,除非您的程序随着时间的推移加载无限数量的模块,否则这不是内存泄漏的来源.模块通常在启动时加载一次,就是这样.你的记忆泄漏很可能在其他地方.
在不太可能的情况下,您的程序确实会随着时间的推移加载无限数量的模块,您应该重新设计您的程序.;-)
mod*_*itt 11
我在 python3(10 年后)(现在)中找不到对此的权威观点python3.8
。然而,我们现在可以在百分比方面做得更好。
import gc
import sys
the_objs = gc.get_objects()
print(len(gc.get_objects())) # 5754 objects in memory
origin_modules = set(sys.modules.keys())
import http.client # it was renamed ;)
print(len(gc.get_objects())) # 9564 objects in memory
for new_mod in set(sys.modules.keys()) - origin_modules:
del sys.modules[new_mod]
try:
del globals()[new_mod]
except KeyError:
pass
try:
del locals()[new_mod]
except KeyError:
pass
del origin_modules
# importlib.invalidate_caches() happens to not do anything
gc.collect()
print(len(gc.get_objects())) # 6528 objects in memory
Run Code Online (Sandbox Code Playgroud)
仅增长13%。如果您查看 new 中加载的对象类型gc.get_objects
,其中一些是内置函数、源代码、random.*
实用程序、datetime
实用程序等。我主要将其保留在这里作为更新以启动 @shuttle 的对话,并将删除如果我们可以取得更大的进步。
我不知道Python,但在其他语言中,调用相当于gc.collect()
确实不释放未使用的内存-如果/当实际所需的内存也只会释放内存。
否则,Python 暂时将模块保存在内存中是有意义的,以防它们需要再次加载。
归档时间: |
|
查看次数: |
18017 次 |
最近记录: |