Python列出异常内存使用情况
我正在做一个项目,涉及访问内存中的一个大列表中的数据。因为这个列表非常庞大(数百万行),所以我会密切关注使用了多少内存。我使用OSX,所以在创建这些列表时保持活动监视器打开 我注意到列表所使用的内存量可能会因其构造方式的不同而大不相同,但我似乎不明白为什么 下面是一些示例代码: (我正在OSX 10.8.3上使用Python 2.7.4) 下面的第一个函数创建一个列表,并用所有相同的三个随机数填充它 下面的第二个函数创建一个列表,并用所有不同的随机数填充它Python列出异常内存使用情况,python,list,memory,Python,List,Memory,我正在做一个项目,涉及访问内存中的一个大列表中的数据。因为这个列表非常庞大(数百万行),所以我会密切关注使用了多少内存。我使用OSX,所以在创建这些列表时保持活动监视器打开 我注意到列表所使用的内存量可能会因其构造方式的不同而大不相同,但我似乎不明白为什么 下面是一些示例代码: (我正在OSX 10.8.3上使用Python 2.7.4) 下面的第一个函数创建一个列表,并用所有相同的三个随机数填充它 下面的第二个函数创建一个列表,并用所有不同的随机数填充它 import random impor
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
在这一点上,我使用的内存增加了大约46MB,这是我从上面给出的信息中所期望的
现在进入下一个功能:
In [4]: thing2 = make_table2(6000000)
In [5]: sys.getsizeof(thing2)
Out[5]: 48000072
如您所见,两个列表占用的内存是相同的。它们的长度完全相同,这是意料之中的。我没想到的是,活动监视器给出的内存使用量超过了1GB
我知道会有一些开销,但20倍多?46MB的列表需要1GB吗
真的吗
好的,继续诊断
我做的第一件事就是收集垃圾:
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.>
[7]中的:来自guppy import hpy
在[8]中:hpy().heap()
出[8]:
一组24217689对象的分区。总大小=1039012560字节。
索引计数%Size%累计%Kind(类/类的目录)
0 6054789 25 48482176847 48482176847元组
18008261 74 432198264 42 917020032 88浮子
2 2267 0 96847576 9 1013867608 98名单
39903200113928801102526048899街
4 585 0 1963224 0 1027223712 99模块目录
51712 0 1799552 0 1029023264 99 dict(无所有者)
6 13606 0 1741568 0 1030764832 99类型。代码类型
7 13355 0 1602600 0 1032367432 99功能
81494 0 1348088 0 1033715520 99型
9 1494 0 1300752 0 1035016272 100型dict
好的,我的记忆被以下内容占据:
462MB的元组(嗯?)
412MB浮点数(什么?)
92MB的列表(好的,这是有意义的。2*46MB=92)
我的名单是预先分配的,所以我不认为会出现分配过度的情况
问题:
为什么这两个非常相似的列表使用的内存量如此不同
有没有一种不同的方法来填充一个没有那么多开销的列表
有没有办法释放所有的记忆
注意:请不要建议存储在磁盘上或使用array.array或numpy或pandas数据结构。这些都是很好的选择,但这个问题与它们无关。这个问题是关于普通的旧列表
我用Python3.3尝试过类似的代码,结果是一样的
这是一个带着一只手的人。它包含了一些提示,但不是同一个问题
谢谢大家! 这两个函数都列出了6000000个引用
sizeof(thelist) ≅ sizeof(reference_to_a_python_object) * 6000000
第一个列表包含对同一个三个浮点元组的6000000个引用
第二个列表包含对6000000个不同元组的引用,其中包含18000000个不同浮点
如您所见,浮点值需要24个字节,三元组需要80个字节(使用您的python构建)。不,除了numpy没有别的办法
要将列表变成可回收垃圾,您需要清除对它们的任何引用:
del thing1
del thing2
您似乎对大小为6000000 x 3的2d数组感兴趣;你看过numpy(例如:
numpy.random.rand(6000000,3)
)