一个包含一百万个元素的列表在 Python 中将占用多少内存?
How much memory will a list with one million elements take up in Python?
,Reddit 上有超过一百万个 subreddits
我写了一个脚本,重复查询 this Reddit API endpoint 直到所有的 subreddits 都存储在一个数组中,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
]
这个列表大约会占用多少space内存?
这取决于您的 Python 版本和您的系统,但我会帮助您计算需要多少内存。首先,sys.getsizeof
仅 returns 表示容器的 对象 的内存使用,而不是容器中的所有元素。
Only the memory consumption directly attributed to the object is
accounted for, not the memory consumption of objects it refers to.
If given, default will be returned if the object does not provide
means to retrieve the size. Otherwise a TypeError will be raised.
getsizeof()
calls the object’s __sizeof__
method and adds an
additional garbage collector overhead if the object is managed by the
garbage collector.
See recursive sizeof recipe for an example of using getsizeof()
recursively to find the size of containers and all their contents.
所以,我已经在交互式解释器会话中加载了该食谱:
因此,CPython list 实际上是一个异构的、可调整大小的数组列表。底层数组仅包含指向 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 对象的开销和底层数组最后留下的额外 space 来考虑,以允许高效的 .append
操作.
现在,字典在 Python 中相当重量级。只是容器:
In [10]: sys.getsizeof({})
Out[10]: 288
所以 100 万个字典的 下限 是:288000000 字节。所以,粗略的下限:
In [12]: 1000000*288 + 1000000*8
Out[12]: 296000000
In [13]: 296000000 * 1e-9 # gigabytes
Out[13]: 0.29600000000000004
因此您可以预期大约 0.3 GB 的内存。使用 recipie 和更现实的 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 场演出。现在,这在现代系统上并不多。但是如果你想保存 space,你应该使用 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
一样工作,但您可以使用 names:
访问字段
In [30]: r = x[0]
In [31]: r.name
Out[31]: 'my name is what'
In [32]: r.subscribers
Out[32]: 23456644
我写了一个脚本,重复查询 this Reddit API endpoint 直到所有的 subreddits 都存储在一个数组中,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
]
这个列表大约会占用多少space内存?
这取决于您的 Python 版本和您的系统,但我会帮助您计算需要多少内存。首先,sys.getsizeof
仅 returns 表示容器的 对象 的内存使用,而不是容器中的所有元素。
Only the memory consumption directly attributed to the object is accounted for, not the memory consumption of objects it refers to.
If given, default will be returned if the object does not provide means to retrieve the size. Otherwise a TypeError will be raised.
getsizeof()
calls the object’s__sizeof__
method and adds an additional garbage collector overhead if the object is managed by the garbage collector.See recursive sizeof recipe for an example of using
getsizeof()
recursively to find the size of containers and all their contents.
所以,我已经在交互式解释器会话中加载了该食谱:
因此,CPython list 实际上是一个异构的、可调整大小的数组列表。底层数组仅包含指向 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 对象的开销和底层数组最后留下的额外 space 来考虑,以允许高效的 .append
操作.
现在,字典在 Python 中相当重量级。只是容器:
In [10]: sys.getsizeof({})
Out[10]: 288
所以 100 万个字典的 下限 是:288000000 字节。所以,粗略的下限:
In [12]: 1000000*288 + 1000000*8
Out[12]: 296000000
In [13]: 296000000 * 1e-9 # gigabytes
Out[13]: 0.29600000000000004
因此您可以预期大约 0.3 GB 的内存。使用 recipie 和更现实的 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 场演出。现在,这在现代系统上并不多。但是如果你想保存 space,你应该使用 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
一样工作,但您可以使用 names:
In [30]: r = x[0]
In [31]: r.name
Out[31]: 'my name is what'
In [32]: r.subscribers
Out[32]: 23456644