大型Python列表的内存要求是什么?
我在做一件傻事,比如:
from itertools import *
rows = combinations(range(0, 1140), 17)
all_rows = []
for row in rows:
all_rows.append(row)
没什么意外,我的内存地址空间用完了(32位的Python 3.1
)。我想问的是:我该怎么计算一个大列表需要多少内存地址空间?在这个例子中,这个列表的大小大约是 2.3X10^37
。Python里有没有什么函数可以告诉我我需要的信息,或者实际上是一个更小但类似的列表的大小?这些工具是什么呢?
4 个回答
补充说明:因为你在处理整数列表,并且担心内存使用问题——这里还有一个 array
模块可以考虑:
[
array
] 定义了一种对象类型,可以紧凑地表示基本值的数组:字符、整数、浮点数。数组是一种序列类型,和列表的行为非常相似,只是存储在其中的对象类型是有限制的。这个类型是在创建对象时指定的 [...].
首先,不要写:
all_rows = []
for row in rows:
all_rows.append(row)
你可以简单地写:
all_rows = list(rows)
这样会更高效一些。
接下来,有两件事需要考虑列表的内存占用:
- 列表中对象的内存占用;这显然取决于这些对象的类型,以及它们是否有很多共享的部分。
- 列表本身的内存占用;列表中的每个对象都是通过一个指针来引用的,在32位模式下这个指针占用4个字节,在64位模式下占用8个字节;所以,简单来说,列表本身的大小是(4或8字节)乘以列表中对象的数量(这里没有考虑固定的列表头部开销和Python列表的适度超分配)。
顺便提一下,在最近的Python版本中,你可以使用 sys.getsizeof()
来获取一个对象的大小:
>>> import sys
>>> sys.getsizeof([None] * 100)
872
有一个很实用的函数 sys.getsizeof()
(从Python 2.6开始就有)可以帮助我们了解对象的内存占用情况:
>>> import sys
>>> sys.getsizeof(1) # integer
12
>>> sys.getsizeof([]) # empty list
36
>>> sys.getsizeof(()) # empty tuple
28
>>> sys.getsizeof((1,)) # tuple with one element
32
从这里你可以看到,每个整数占用12个字节,而在列表或元组中,每个引用占用4个字节(在32位机器上),再加上额外的开销(分别是36或28个字节)。
如果你的结果是长度为17的元组,里面全是整数,那么每个元组的内存占用就是 17*(12+4)+28
,也就是300个字节。结果本身是一个列表,所以它占用36个字节,加上每个引用4个字节。你只需要找出这个列表的长度(我们称它为N),那么总的内存需求就是 36+N*(4+300)
。
补充:还有一件事可能会显著影响这个结果。Python会根据需要创建新的整数对象,但对于一些小的整数(在Windows上的Python 2.6.4中,范围是[-5, 256]),它会提前创建好并重复使用。如果你的值中有很大一部分小于257,这样会大大减少内存的使用。(在Python中,257并不等于257+0
;-))。