Python 列出异常内存使用情况

标签 python list memory

我正在开展一个项目,该项目涉及从保存在内存中的大型列表中访问数据。因为列表非常庞大(数百万行),所以我密切关注正在使用的内存量。我使用 OS X,因此在创建这些列表时会保持事件监视器打开。

我注意到列表使用的内存量可能会根据其构造方式而有很大差异,但我似乎无法弄清楚原因。

现在是一些示例代码:

(我在 OSX 10.8.3 上使用 Python 2.7.4)

下面的第一个函数创建一个列表并用相同的三个随机数填充它。

下面的第二个函数创建一个列表并用所有不同的随机数填充它。

import random
import sys


def make_table1(size):
    list1 = size *[(float(),float(),float())] # initialize the list
    line = (random.random(), 
            random.random(), 
            random.random())
    for count in xrange(0, size): # Now fill it
        list1[count] = line
    return list1

def make_table2(size):
    list1 = size *[(float(),float(),float())] # initialize the list
    for count in xrange(0, size): # Now fill it
        list1[count] = (random.random(), 
                        random.random(), 
                        random.random())
    return list1

(首先让我说,我意识到上面的代码可以写得更有效率。这样写是为了让两个示例尽可能相似。)

现在我使用这些函数创建一些列表:

In [2]: thing1 = make_table1(6000000)

In [3]: sys.getsizeof(thing1)
Out[3]: 48000072

此时我使用的内存增加了大约 46 MB,这是我从上面给出的信息中所期望的。

现在开始下一个函数:

In [4]: thing2 = make_table2(6000000)

In [5]: sys.getsizeof(thing2)
Out[5]: 48000072

如你所见,两个列表占用的内存是一样的。它们的长度完全相同,因此这是意料之中的。令我没想到的是,我的 Activity Monitor 使用的内存跃升到了 1 GB 以上!

我知道会有一些开销,但要多 20 倍? 46MB 列表需要 1 GB?

真的吗?

好的,开始诊断...

我尝试的第一件事是收集任何垃圾:

In [5]: import gc

In [6]: gc.collect()
Out[6]: 0

它使使用的内存量为零。

接下来我用 guppy 来查看内存的去向:

In [7]: from guppy import hpy

In [8]: hpy().heap()

Out[8]: 
Partition of a set of 24217689 objects. Total size = 1039012560 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0 6054789  25 484821768  47 484821768  47 tuple
     1 18008261  74 432198264  42 917020032  88 float
     2   2267   0 96847576   9 1013867608  98 list
     3  99032   0 11392880   1 1025260488  99 str
     4    585   0  1963224   0 1027223712  99 dict of module
     5   1712   0  1799552   0 1029023264  99 dict (no owner)
     6  13606   0  1741568   0 1030764832  99 types.CodeType
     7  13355   0  1602600   0 1032367432  99 function
     8   1494   0  1348088   0 1033715520  99 type
     9   1494   0  1300752   0 1035016272 100 dict of type
<691 more rows. Type e.g. '_.more' to view.>

好的,我的内存被占用了:

462 MB 的元组(嗯?)

412 MB 的 float (什么?)

92 MB 的列表(好吧,这个有意义。2*46MB = 92)

我的列表是预先分配的,所以我认为没有过度分配。

问题:

为什么这两个非常相似的列表使用的内存量如此不同?

有没有其他方法来填充没有太多开销的列表?

有没有办法释放所有内存?

注意:请不要建议存储在磁盘上或使用 array.array 或 numpy 或 pandas 数据结构。这些都是不错的选择,但这个问题与它们无关。这个问题是关于普通的旧列表。

我用 Python 3.3 尝试过类似的代码,结果是一样的。

这里有人拥有 similar problem .它包含一些提示,但不是同一个问题。

谢谢大家!

最佳答案

这两个函数都列出了 6000000 个引用。

sizeof(thelist) ≅ sizeof(reference_to_a_python_object) * 6000000

第一个列表包含 6000000 个对三个 float 的同一个元组的引用。

第二个列表包含对包含 18000000 个不同 float 的 6000000 个不同元组的引用。

enter image description here

如您所见, float 需要 24 个字节,而三元组需要 80 个字节(使用您的 python 构建)。不,除了 numpy 没有其他办法。

要将列表变成可收集的垃圾,您需要删除对它们的任何引用:

del thing1 
del thing2

关于Python 列出异常内存使用情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16492851/

相关文章:

python - 创建一个字典,其值每次使用时都会更新

java - 在集合类型之间转换是否被认为是错误的形式?

java - Java 多态中对象的字段访问和内存分配

c# - 实例化一个对象时,它是否都存储在内存中?

c - glClear 函数 : Question about the parameters

python - ping一个网站地址返回一个IP

python - 将 netcdf 文件的所有时间步长绘制成 map

python - 使用 python statsmodels 修复summary_col 中的标签外生变量

c# - 如何在最后一个列表中插入元素?

java - 如何在java中为列表分配对象类型?