【问题标题】:python memory reclaim about dict and listpython关于dict和list的内存回收
【发布时间】:2013-06-03 18:26:41
【问题描述】:

最近,我对 python 的内存管理感到困惑。首先是关于 dict,说我有 一个复合 dict 对象,如

d = {id1: {'x': 'a', 'y': [1,2,3], 'z': {'k', 'v'}}, id2: {...}}

如果我调用 del,

del d[id1]

d[id1]['y'] 和 d[id1]['z'] 会一起回收吗?

第二个是关于列表的,我看了here的答案,所以我试了一下。这是我的代码

import sys
import gc
import time
from collections import defaultdict 
from pprint import pprint 

def f():
    d = defaultdict(int) 
    objects = gc.get_objects() 
    for o in objects: 
        d[type(o)] += 1
    x = d.items()
    x = sorted(x, key=lambda i: i[1], reverse=True)
    pprint(x[:5]) 

def loop():
    while True:
        leaked = [[x] for x in range(100)]
        f()
        time.sleep(0.1)

当范围是 100 时,函数 f 确实向我显示列表在增加,但是当 我将范围修改为1000,没有什么可改变的,列表的数量保持不变。 谁能告诉我这是什么问题?

【问题讨论】:

    标签: python memory


    【解决方案1】:

    “d[id1]['y']和d[id1]['z']会一起回收吗?”

    假设没有其他内容引用该字典或其中的内容,那么它会同时达到 0 引用计数。但是,不能保证会立即收集到其中的任何内容。

    “....谁能告诉我有什么问题?”

    Python 缓存低整数对象,因此它们将始终被引用:

    http://docs.python.org/2/c-api/int.html - “当前的实现为 -5 到 256 之间的所有整数保留一个整数对象数组,当您在该范围内创建一个 int 时,实际上您只是返回对现有对象的引用。”

    这可以解释您所看到的行为。不要在 range(100) 中使用 x,而是创建匿名对象,例如

    leaked = [object() for x in range(100)]
    

    【讨论】:

    • 是的,当我使用匿名对象时, 没有增长,但是 一直在继续,看起来很奇怪
    【解决方案2】:

    del 删除对当前命名空间中对象的引用。 在 Cpython 中,当一个对象的引用计数达到 0 时,它将可供 python 用于将来的对象(不一定回到操作系统)。

    考虑:

    a = []
    b = a
    del a #The list doesn't get freed because `b` is still a reference to that list
    

    在您的场景中,当您 del d[id1] 时,您删除了对该(内部)字典的引用。由于它持有一堆对其他对象的引用,因此这些对象中的每一个现在都少了 1 个引用。如果它们的引用计数达到 0,它们将被收集,并且它们持有引用的每个对象的引用计数都会递减,依此类推。

    【讨论】:

      猜你喜欢
      • 2011-08-28
      • 2011-08-07
      • 2019-07-28
      • 1970-01-01
      • 2020-12-05
      • 1970-01-01
      • 1970-01-01
      • 2013-06-02
      • 1970-01-01
      相关资源
      最近更新 更多