Python中包含一百万个元素的列表会占用多少内存?

时间:2017-04-14 02:01:07

标签: python arrays memory reddit

根据{{​​3}},Reddit上有超过一百万个子评价。

我编写了一个脚本,反复查询redditmetrics.com,直到所有子编辑都存储在数组中all_subs

all_subs = []
for sub in <repeated request here>:
    all_subs.append({"name": display_name, "subscribers": subscriber_count})

该脚本已经运行了近十个小时,大约已经完成了一半(每三个或四个请求就会受到速率限制)。当它完成后,我期待一个像这样的数组:

[
    { "name": "AskReddit", "subscribers", 16751677 },
    { "name": "news", "subscribers", 13860169 },
    { "name": "politics", "subscribers", 3350326 },
    ... # plus one million more entries
]

此列表占用的内存空间大约占多少?

1 个答案:

答案 0 :(得分:13)

这取决于你的Python版本和你的系统,但我会帮你弄清楚需要多少内存。首先,sys.getsizeof仅返回表示容器的对象的内存使用,而不是容器中的所有元素。

  

只有直接归因于对象的内存消耗才是   占了,而不是它所指对象的内存消耗。

     

如果给定,则在对象未提供时将返回default   意味着检索大小。否则会引发TypeError。

     

getsizeof()调用对象的__sizeof__方法并添加一个   如果对象由管理,则额外的垃圾收集器开销   垃圾收集器。

     

有关使用getsizeof()的示例,请参阅recursive sizeof recipe   递归地查找容器及其所有内容的大小。

所以,我在交互式翻译会话中加载了这个食谱:

因此,CPython 列表实际上是一个异质的,可调整大小的arraylist。底层数组只包含指向Py_Objects的指针。因此,指针占用了一个值得记忆的机器字。在64位系统上,这是64位,因此是8个字节。因此,仅用于容器大小为1,000,000的列表将占用大约800万字节或8兆字节。建立一个包含1000000个条目的列表可以解决这个问题:

In [6]: for i in range(1000000):
   ...:     x.append([])
   ...:

In [7]: import sys

In [8]: sys.getsizeof(x)
Out[8]: 8697464

额外的内存由python对象的开销和底层数组在末尾留下的额外空间来计算,以便进行高效的.append操作。

现在,字典在Python中相当重要。只是容器:

In [10]: sys.getsizeof({})
Out[10]: 288

因此,大小为100万个dicts的下限是:288000000个字节。所以,粗略的下限:

In [12]: 1000000*288 + 1000000*8
Out[12]: 296000000

In [13]: 296000000 * 1e-9 # gigabytes
Out[13]: 0.29600000000000004

所以你可以期待大约0.3千兆字节的内存。使用收件人和更真实的dict

In [16]: x = []
    ...: for i in range(1000000):
    ...:     x.append(dict(name="my name is what", subscribers=23456644))
    ...:

In [17]: total_size(x)
Out[17]: 296697669

In [18]:

所以,约0.3演出。现在,在现代系统上并不是很多。但是如果你想节省空间,你应该使用tuple甚至更好的namedtuple

In [24]: from collections import namedtuple

In [25]: Record = namedtuple('Record', "name subscribers")

In [26]: x = []
    ...: for i in range(1000000):
    ...:     x.append(Record(name="my name is what", subscribers=23456644))
    ...:

In [27]: total_size(x)
Out[27]: 72697556

或者,以千兆字节为单位:

In [29]: total_size(x)*1e-9
Out[29]: 0.07269755600000001

namedtuple就像tuple一样,但您可以使用名称访问字段:

In [30]: r = x[0]

In [31]: r.name
Out[31]: 'my name is what'

In [32]: r.subscribers
Out[32]: 23456644