对象的Python列表占用了太多内存

时间:2015-03-11 11:46:12

标签: python list python-3.x memory

我有以下代码,它创建了一个类foo的百万个对象:

for i in range(1000000):
    bar = foo()
    list_bar.append(bar)

bar对象只有96个字节,由getsizeof()确定。然而,追加步骤需要几乎8GB的内存。一旦代码退出循环,ram使用量就会下降到预期的数量(列表的大小+一些开销~103MB)。只有在循环运行时,ram使用才会飙升。为什么会这样?任何解决方法? PS:使用生成器不是一个选项,它必须是一个列表。

编辑: xrange没有帮助,使用Python 3.内存使用率仅在循环执行期间保持高水平,并在循环结束后停止。 append可能有一些不明显的开销吗?

2 个答案:

答案 0 :(得分:5)

最有可能的原因是foo()构造函数引发了一些非预期的循环引用;因为通常Python对象会在引用计数降至零时立即释放内存;现在,当垃圾收集器有机会运行时,这些将被释放。

您可以尝试在10000次迭代后强制运行GC以查看它是否保持内存使用量不变。

import gc
n = 1000000
list_bar = [ None ] * n
for i in range(n):
    list_bar[i] = foo()
    if i % 10000 == 0:
        gc.collect()

如果这样可以减轻内存压力,那么内存使用量是因为某些参考周期。


列表的大小调整有一些开销。如果你知道有多少元素,那么你可以事先创建列表,例如:

list_bar = [ foo() for _ in xrange(1000000) ]

应该知道数组的大小而不需要调整它的大小;或创建填充None的列表:

n = 1000000
list_bar = [ None ] * n
for i in range(n):
    list_bar[i] = foo()

append应该使用realloc来扩展列表,但是旧内存应该尽快释放;并且所有分配的所有内存的开销都不应该总和到8G,最后是100 MB的列表;操作系统可能错误地计算了使用的内存。

答案 1 :(得分:0)

您如何衡量内存使用情况?

我怀疑您使用第三方模块可能是原因。也许第三方模块在初始化时暂时使用大量内存。

此外,sys.getsizeof()不能准确指示对象使用的内存。

例如:

from sys import getsizeof

class A(object):
    pass

class B(object):
    def __init__(self):
        self.big = 'a' * 1024*1024*1024    # approx. 1 GiB

>>> getsizeof(A)
976
>>> a = A()
>>> getsizeof(a)
64
>>> 
>>> getsizeof(B)
976
>>> b = B()
>>> getsizeof(b)
64
>>> getsizeof(b.big)
1073741873

实例化b = B()后,top报告大约1GiB驻留内存使用情况。显然,getsizeof(b)没有反映出这只返回64个字节。