为什么Python列表切片赋值会占用内存?

6

我正在处理一个Python项目中的内存泄漏问题,并且已经花费了很多时间。我将问题归纳为一个小例子。现在看起来我知道解决方案,但是我无法理解为什么。

import random

def main():
    d = {}
    used_keys = []
    n = 0
    while True:
        # choose a key unique enough among used previously
        key = random.randint(0, 2 ** 60)
        d[key] = 1234 # the value doesn't matter
        used_keys.append(key)
        n += 1
        if n % 1000 == 0:
            # clean up every 1000 iterations
            print 'thousand'
            for key in used_keys:
                del d[key]
                used_keys[:] = []
                #used_keys = []

if __name__ == '__main__':
    main()

我的想法是将一些值存储在字典d中,并在列表中记住已使用的键,以便能够定期从字典中清除它们。

这个程序的变体自信地消耗内存,却从不释放。如果我使用在示例中被注释的“清除”used_keys的替代方法,一切都很好:内存消耗保持在恒定水平。

为什么?

已在CPython和许多Linux系统上进行了测试。


你怎么确定它永远不会返回呢?可能只是操作系统从未要求它返回。 - detly
2
清空used_keys不应该在for key in used_keys循环之外吗? - adamk
2
我的想法是将一些值存储在字典d中,并将使用过的键记忆在列表中,以便能够定期清理字典。为什么不直接使用d.keys()呢?它将是相同的键列表。 - Daniel Kluev
@adamk 请看已接受答案下的评论。 @Daniel 和 @gnibbler 这只是一个模型,如果它是独立的代码,我不会使用这样奇怪的方法。 - nkrkv
2个回答

5
这是原因 - 当前的方法并没有从字典中删除键(实际上只有一个)。这是因为您在循环期间清除了used_keys列表,导致循环过早退出。
然而,第二种(已注释)方法可以工作,因为您将新值分配给了used_keys,所以循环成功完成。
请看以下示例:
>>> a=[1,2,3]
>>> for x in a:
...    print x
...    a=[]
...
1
2
3

并且

>>> a=[1,2,3]
>>> for x in a:
...    print x
...    a[:] = []
...
1
>>>

1
啊!! 我太蠢了,太蠢了。我很高兴能在一个小片段中重构内存泄漏...... 当然这是个悲哀的错误。它并没有代表我的问题,我会继续寻找。但你对原始问题的答案是正确的。谢谢! - nkrkv

0

为什么这样的东西不起作用呢?

from itertools import count
import uuid

def main():
    d = {}
    for n in count(1):
        # choose a key unique enough among used previously
        key = uuid.uuid1()
        d[key] = 1234 # the value doesn't matter
        if n % 1000 == 0:
            # clean up every 1000 iterations
            print 'thousand'
            d.clear()

if __name__ == '__main__':
    main()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接