我只是试验了内存中 python 数据结构的大小。我写了以下片段:
import sys
lst1=[]
lst1.append(1)
lst2=[1]
print(sys.getsizeof(lst1), sys.getsizeof(lst2))
我在以下配置上测试了代码:
- Windows 7 64 位,Python3.1:输出为:
52 40
所以 lst1 有 52 个字节,lst2 有 40 个字节。 - 带有 Python3.2 的 Ubuntu 11.4 32 位:输出是
48 32
- Ubuntu 11.4 32 位 Python2.7:
48 36
谁能向我解释为什么这两个大小不同,尽管它们都是包含 1 的列表?
在 getsizeof 函数的 python 文档中,我发现了以下内容: ...adds an additional garbage collector overhead if the object is managed by the garbage collector.
在我的小示例中可能是这种情况吗?
原文由 halex 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是一个更完整的交互式会话,可以帮助我解释发生了什么(Windows XP 32 位上的 Python 2.6,但这并不重要):
请注意,空列表比其中包含
[1]
的列表小一点。但是,当追加一个元素时,它会变得更大。原因是 CPython 源代码中
Objects/listobject.c
中的实现细节。空列表
创建空列表
[]
时,不会为元素分配空间 - 这可以在PyList_New
中看到。 36 字节是列表数据结构本身在 32 位机器上所需的空间量。包含一个元素的列表
当创建具有单个元素的列表
[1]
时,除了列表数据结构本身所需的内存之外,还会为一个元素分配空间。同样,这可以在PyList_New
中找到。给定size
作为参数,它计算:然后有:
所以我们看到
size = 1
,分配了一个指针的空间。 4 个字节(在我的 32 位机器上)。追加到一个空列表
在空列表上调用
append
时,会发生以下情况:PyList_Append
调用app1
app1
询问列表的大小(并得到 0 作为答案)app1
然后调用list_resize
size+1
(在我们的例子中是1)list_resize
有一个有趣的分配策略,从其来源的评论中总结。这里是:
让我们做一些数学
让我们看看我在文章开头的会话中引用的数字是如何达到的。
所以 36 字节是列表数据结构本身在 32 位上所需的大小。对于单个元素,空间被分配给一个指针,所以这是 4 个额外的字节——总共 40 个字节。好的到目前为止。
当在空列表上调用
app1
时,它调用list_resize
和size=1
。根据list_resize
的过度分配算法,1 之后的下一个最大可用大小是 4,因此将分配 4 个指针的位置。 4 * 4 = 16 字节,36 + 16 = 52。确实,一切都说得通:-)