添加列表值时的内存泄漏

2 投票
1 回答
1758 浏览
提问于 2025-04-29 12:32

我刚接触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 = 这一行后面,似乎是最明显的地方。)

撰写回答