这是一个更完整的交互式会议,它将帮助我解释发生了什么(Windows XP 32位上的Python 2.6,但这并不重要):
>>> import sys>>> sys.getsizeof([])36>>> sys.getsizeof([1])40>>> lst = []>>> lst.append(1)>>> sys.getsizeof(lst)52>>>
请注意,空列表要比其中的空列表小一些
[1]。但是,添加元素后,它会变得更大。
原因是
Objects/listobject.cCPython源代码中的实现细节。
空清单
[]创建空列表时,不会为元素分配空间-在中可以看到
PyList_New。36字节是32位计算机上列表数据结构本身所需的空间量。
列出一个元素
[1]创建具有单个元素的列表时,除了列表数据结构本身所需的内存外,还为一个元素分配了空间。同样,可以在中找到
PyList_New。鉴于
size作为参数,它计算:
nbytes = size * sizeof(PyObject *);
然后具有:
if (size <= 0) op->ob_item = NULL;else { op->ob_item = (PyObject **) PyMem_MALLOC(nbytes); if (op->ob_item == NULL) { Py_DECREF(op); return PyErr_NoMemory(); } memset(op->ob_item, 0, nbytes);}Py_SIZE(op) = size;op->allocated = size;因此,我们看到有了
size = 1,分配了一个指针的空间。4个字节(在我的32位框中)。
追加到空列表
呼叫
append空白清单时,会发生以下情况:
PyList_Append
来电app1
app1
询问列表的大小(并得到0作为答案)app1
然后list_resize
以size+1
(在我们的例子中为1)进行呼叫list_resize
有一个有趣的分配策略,此注释从其来源进行了总结。
这里是:
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);if (new_allocated > PY_SIZE_MAX - newsize) { PyErr_NoMemory(); return -1;} else { new_allocated += newsize;}让我们做一些数学
让我们看看如何达到在本文开头的会话中引用的数字。
因此,列表数据结构本身在32位上所需的大小为36个字节。对于单个元素,将为一个指针分配空间,因此这是4个额外的字节-总共40个字节。到目前为止还可以。
在
app1空白列表中调用
list_resize时,会使用调用
size=1。根据的过度分配算法
list_resize,1之后的下一个最大可用大小为4,因此将分配4个指针的位置。4* 4 = 16个字节,36 + 16 = 52。
确实,一切都说得通:-)



