添加列表值时的内存泄漏
我刚接触Python,遇到了一个大内存问题。我的脚本全天候运行,每天大约会多占用1GB的内存。我发现问题可能出在这个函数上:
代码:
#!/usr/bin/env python
# coding: utf8
import gc
from pympler import muppy
from pympler import summary
from pympler import tracker
v_list = [{
'url_base' : 'http://www.immoscout24.de',
'url_before_page' : '/Suche/S-T/P-',
'url_after_page' : '/Wohnung-Kauf/Hamburg/Hamburg/-/-/50,00-/EURO--500000,00?pagerReporting=true',}]
# returns url
def get_url(v, page_num):
return v['url_base'] + v['url_before_page'] + str(page_num) + v['url_after_page']
while True:
gc.enable()
for v_idx,v in enumerate(v_list):
# mem test ouput
all_objects = muppy.get_objects()
sum1 = summary.summarize(all_objects)
summary.print_(sum1)
# magic happens here
url = get_url(v, 1)
# mem test ouput
all_objects = muppy.get_objects()
sum1 = summary.summarize(all_objects)
summary.print_(sum1)
# collects unlinked objects
gc.collect()
输出:
======================== | =========== | ============
list | 26154 | 10.90 MB
str | 31202 | 1.90 MB
dict | 507 | 785.88 KB
特别是这个列表属性,每次循环都会变得越来越大,大约增加600KB,我不知道为什么。我觉得我并没有在这里存储任何东西,而且url变量应该每次都被覆盖。所以理论上来说,内存不应该有任何消耗。
我这里漏掉了什么呢?:-)
1 个回答
3
这个“内存泄漏”完全是因为你在测试内存泄漏。all_objects
列表里保存了你创建的几乎所有对象——甚至是那些你已经不需要的对象。如果这些对象不在 all_objects
里,它们本来会被清理掉,但现在它们却被保留了。
做个简单的测试:
如果我直接运行这段代码,
list
的值每次大约增长600KB,就像你在问题中说的那样,至少增长到20MB,我才停止它。但是如果我在
sum1 =
这一行后面加上del all_objects
,那么list
的值就在100KB和650KB之间来回波动。
想想为什么会这样,其实回头看就很明显。当你调用 muppy.get_objects()
(除了第一次)时,之前的 all_objects
的值仍然存在。所以,它是返回的对象之一。这意味着,即使你把返回的值赋给 all_objects
,你并没有释放旧的值,你只是把它的引用计数从2降到1。这不仅保留了旧的值本身,还保留了它里面的每一个元素——根据定义,这就是上一次循环中所有存活的东西。
如果你能找到一个内存探索库,能给你弱引用而不是普通引用,那可能会有帮助。否则,确保在再次调用 muppy.get_objects
之前,某个时刻执行 del all_objects
。(在你唯一使用它的地方,也就是 sum1 =
这一行后面,似乎是最明显的地方。)