为啥相同对象的内存空间分配不同?
Posted
技术标签:
【中文标题】为啥相同对象的内存空间分配不同?【英文标题】:Why memory space allocation is different for the same objects?为什么相同对象的内存空间分配不同? 【发布时间】:2021-05-16 14:19:59 【问题描述】:我正在试验 Python 如何分配内存,所以发现了同样的问题,例如
Size of list in memory 和 Eli 以更好的方式进行了描述。他的回答让我产生了新的疑问,我检查了1 + [] and [1]
的大小,但正如您在代码 sn-p 中看到的那样,它是不同的。如果我没记错内存空间分配应该是一样的。但事实并非如此。任何人都可以帮助我理解吗?
>>> import sys
>>> sys.getsizeof(1)
28
>>> sys.getsizeof([])
64
>>> 28 + 64
92
>>> sys.getsizeof([1])
72
【问题讨论】:
我真的不明白你不明白什么。你在哪里比较相同对象的大小......但也许你缺少的是sys.getsizeof
只给你对象本身的大小,而不是任何其他可能被引用的对象论点。所以,[1]
的大小只是列表对象,它在后台包含一个 PyObject 指针数组。
这是因为列表包含对其他对象的引用。引用的sizeof
是 72-64=8。所以你可以把很多大元素放到你的列表中,但是列表的大小仍然是 64+(8*len) (我在这里跳过了关于列表调整大小分配的步骤,所以这只是 mostly 准确)。每个对象依次将占用所需的空间(在您的情况下为 28 个)
添加另一个怪癖,而 1
是 28 字节大,它是 CPython 中的 cached integer。只有引用实际上需要另一个分配。不过,该引用有 8 个字节大,array
存储可能会更有效。
@YannVernier 缓存与它无关(除非您指的是可从列表引用访问的总内存)。列表的元素总是对其他对象的引用。
它仅与列出的数字间接相关,但与考虑使用多少内存以及发生哪些动态分配有关。缓存的整数是预先分配的,小整数保持 28 字节(在那个 64 位系统上),长整数可以更大。由于询问者希望整数驻留在列表中,因此知道它实际存储在哪里可能是相关的。旁注:虽然列表只保存引用,但数组确实保存值。这带来了另一个成本,因为提取它们必须转换为 Python 对象。
【参考方案1】:
列表运行所需的最少信息是什么?
-
某种***列表对象,包含对类信息(方法、类型信息等)的引用,以及列表自身的实例数据
存储在列表中的实际对象
...这会让你得到你期望的大小。但够了吗?
一个固定大小的列表对象只能跟踪固定数量的列表条目:传统上只有一个(头)或两个(头和尾)。 向列表中添加更多的条目并不会改变列表对象本身的大小,因此必须有一些额外的信息:列表元素之间的关系。
可以将这些信息存储在每个 Object 中(这称为侵入式列表),但限制非常严格:每个 Object 一次只能存储在一个列表中。
由于 Python 列表显然不是那样的行为,我们知道这个额外的信息并不已经在列表元素中,而且它不能在列表对象中,所以它必须存储在其他地方。这会增加列表的总大小。
注意。我故意使这个论点相当抽象。您可以通过几种不同的方式实现 list,但它们都不能避免为元素关系提供一些额外的存储空间,即使表示不同。
【讨论】:
这个答案的大部分描述了一个链表,而不是一个 Python 列表(它通常实现为一个动态大小的参考数组)。 在这种情况下,额外的分配是参考数组本身以及其中的任何松弛分配。关键是,无论实现细节如何,都需要存储比 OP 预期更多的信息。这就是为什么我非常小心地准确地说出来的原因。也许我应该把最后一段移到顶部?以上是关于为啥相同对象的内存空间分配不同?的主要内容,如果未能解决你的问题,请参考以下文章