Python对象以什么结构存储在内存中?

Python对象以什么结构存储在内存中?,第1张

Python对象以什么结构存储在内存中?

这取决于哪种对象,以及哪种Python实现:-)

大多数
人使用的CPython中,

python
所有Python对象均由C结构表示
PyObject
。所有“存储对象”的内容实际上都存储一个
PyObject*
。该
PyObject
结构保留了最少的信息:对象的类型(指向另一个的指针
PyObject
)及其引用计数(
ssize_t
-size的整数)。用C定义的类型为该结构扩展了它们需要存储在对象本身中的额外信息,有时还会分配额外的数据

例如,元组(实现为

PyTupleObject
PextObject结构的“扩展”)存储它们的长度和
PyObject
它们包含在结构本身内部的指针(该结构在定义中包含一个1长度的数组,但是该实现分配了一个内存块)。正确的大小以容纳该
PyTupleObject
结构,再加上与元组应容纳的项目一样多的项目。)以同样的方式,字符串(
PyStringObject
)存储其长度,其缓存的哈希值,一些字符串缓存(“内部”)簿记以及的实际char
*他们的数据。因此,元组和字符串是单个内存块。

另一方面,列表(

PyListObject
)存储它们的长度,一个
PyObject**
用于存储数据的长度,另一个
ssize_t
用于跟踪它们为数据分配的空间。由于Python将
PyObject
指针存储在各处,因此一旦分配PyObject结构就无法对其进行扩展-
这样做可能需要移动该结构,这意味着必须找到所有指针并对其进行更新。因为列表可能需要增长,所以它必须与PyObject结构分开分配数据。元组和字符串不能增长,因此它们不需要。Dicts(
PyDictObject
)以相同的方式工作,尽管它们存储键,键的值和缓存的hashvalue而不是项。Dict还具有一些额外的开销,以适应小词典和专门的查找功能。

但是这些都是C语言中的类型,通常您只需查看C源代码就可以看到它们将使用多少内存。用 Python
而不是C定义的类的实例并不是那么容易。最简单的情况是经典类的实例,并不是那么困难:将a

PyObject
存储
PyObject*
到其类中(与
PyObject
已经存储在struct中的类型不同),将a存储
PyObject*
到其
__dict__
属性(包含所有其他实例属性) )和
PyObject*
其弱引用列表(由
weakref
模块使用,并且仅在必要时初始化)。
__dict__
通常是实例唯一的,因此在计算此类实例的“内存大小”时,您通常还希望计算属性字典的大小。但这不必特定于实例!
__dict__
可以分配就好了。

新型类使举止复杂化。与经典类不同,新类的实例不是单独的C类型,因此它们不需要单独存储对象的类。他们也有余地

__dict__
和weakreflist参考,但不同于经典的情况下,他们并不
需要
__dict__
任意属性的属性。如果该类(及其所有基类)用于
__slots__
定义一组严格的属性,并且这些属性均未命名
__dict__
,则该实例不允许使用任意属性,并且不会分配dict。另一方面,由定义的属性
__slots__
必须存储在
某处
。这是通过存储
PyObject
直接在PyObject结构中指向这些属性值的指针,就像用C语言编写的类型一样。
__slots__
因此
PyObject*
,无论是否设置了该属性,in中的每个条目都将占用a 。

综上所述,问题仍然在于,由于Python中的所有内容都是一个对象,而所有保存对象的内容都只包含一个引用,因此有时很难在对象之间划清界限。两个对象可以引用相同的数据位。他们可能只拥有对该数据的两个引用。摆脱两个对象也摆脱数据。他们俩都拥有数据吗?仅其中之一吗?如果是,哪一个呢?还是您会说他们拥有一半的数据,即使摆脱一个对象不会释放一半的数据呢?弱引用会使情况变得更加复杂:两个对象可以引用相同的数据,但是删除其中一个对象可能会导致另一个对象
摆脱其对该数据的引用,从而导致最终清除该数据。

幸运的是,这种 常见 情况很容易弄清楚。有一些用于Python的内存调试器在跟踪这些事情方面做得很合理,例如heapy。只要您的类(及其基类)相当简单,就可以对它会占用多少内存(尤其是大量内存)进行有根据的猜测。如果您真的想知道数据结构的确切大小,请查阅CPython资料;大多数内置类型是在中描述

Include/<type>object.h
和实现的简单结构
Objects/<type>object.c
。PyObject结构本身在中进行了描述
Include/object.h
。请记住:它一直是指针。那些也占用空间。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5668665.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存