例如,存储一百万(32 位)整数的列表需要多少内存?
alist = range(1000000) # or list(range(1000000)) in Python 3.0
例如,存储一百万(32 位)整数的列表需要多少内存?
alist = range(1000000) # or list(range(1000000)) in Python 3.0
“这取决于。” Python 以这样一种方式为列表分配空间,以实现将元素附加到列表的摊销常数时间。
在实践中,这对当前实现意味着......列表总是为元素的二次幂分配空间。所以 range(1000000) 实际上会分配一个足够大的列表来容纳 2^20 个元素(~ 104.5 万)。
这只是存储列表结构本身所需的空间(它是指向每个元素的 Python 对象的指针数组)。32 位系统每个元素需要 4 个字节,64 位系统每个元素需要 8 个字节。
此外,您需要空间来存储实际元素。这变化很大。对于小整数(目前是 -5 到 256),不需要额外的空间,但对于较大的数字,Python 会为每个整数分配一个新对象,这需要 10-100 个字节并且往往会导致内存碎片化。
底线:它很复杂,Python 列表不是存储大型同构数据结构的好方法。为此,请使用该array
模块,或者,如果您需要进行矢量化数学,请使用 NumPy。
PS-元组与列表不同,它的设计目的不是让元素逐渐附加到它们上面。我不知道分配器是如何工作的,但甚至不考虑将它用于大型数据结构:-)
有用的链接:
然而,他们并没有给出明确的答案。要走的路:
使用/不使用列表测量 Python 解释器消耗的内存(使用 OS 工具)。
使用定义某种 sizeof(PyObject) 的第三方扩展模块。
更新:
import asizeof
N = 1000000
print asizeof.asizeof(range(N)) / N
# -> 20 (python 2.5, WinXP, 32-bit Linux)
# -> 33 (64-bit Linux)
解决问题的“元组”部分
在典型的构建配置中声明 CPython 的 PyTuple 可以归结为:
struct PyTuple {
size_t refcount; // tuple's reference count
typeobject *type; // tuple type object
size_t n_items; // number of items in tuple
PyObject *items[1]; // contains space for n_items elements
};
PyTuple 实例的大小在构建过程中是固定的,之后无法更改。PyTuple 占用的字节数可以计算为
sizeof(size_t) x 2 + sizeof(void*) x (n_items + 1)
.
这给出了元组的浅大小。要获得完整大小,您还需要添加以PyTuple::items[]
数组为根的对象图消耗的总字节数。
值得注意的是,元组构造例程确保只创建空元组的单个实例(单例)。
一个新函数
getsizeof()
接受一个 Python 对象并返回该对象使用的内存量,以字节为单位。内置对象返回正确的结果;第三方扩展可能没有,但可以定义一个__sizeof__()
方法来返回对象的大小。
kveretennicov@nosignal:~/py/r26rc2$ ./python
Python 2.6rc2 (r26rc2:66712, Sep 2 2008, 13:11:55)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
>>> import sys
>>> sys.getsizeof(range(1000000))
4000032
>>> sys.getsizeof(tuple(range(1000000)))
4000024
显然返回的数字不包括包含的对象消耗的内存(sys.getsizeof(1) == 12)。
这是特定于实现的,我很确定。当然,这取决于整数的内部表示——你不能假设它们会被存储为 32 位,因为 Python 为你提供了任意大的整数,所以小整数可能存储得更紧凑。
在我的 Python(核心 2 duo 上的 Fedora 9 上的 2.5.1)上,分配前的 VmSize 为 6896kB,之后为 22684kB。再分配一百万个元素后,VmSize 变为 38340kB。对于 1000000 个整数,这非常粗略地表明大约 16000kB,即每个整数大约 16 个字节。这表明列表的开销很大。我会用一大撮盐来接受这些数字。