您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

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

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

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

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

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

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

但是这些都是C语言中的类型,通常您只需查看C源代码就可以看到它们将使用多少内存。用 Python 而不是C定义的类的实例并不是那么容易。最简单的情况是经典类的实例,并不是那么困难:将a@H_419_5@PyObject存储@H_419_5@PyObject *到其类中(与@H_419_5@PyObject已经存储在struct中的类型不同),将a存储@H_419_5@PyObject *到其@H_419_5@__dict__属性(包含所有其他实例属性) )和@H_419_5@PyObject *其弱引用列表(由@H_419_5@weakref模块使用,并且仅在必要时初始化)。@H_419_5@__dict__通常是实例唯一的,因此在计算此类实例的“内存大小”时,您通常还希望计算属性字典的大小。但这不必特定于实例!@H_419_5@__dict__可以分配就好了。

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

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

幸运的是,这种 常见 情况很容易弄清楚。有一些用于Python的内存调试器在跟踪这些事情方面做得很合理,例如heapy。只要您的类(及其基类)相当简单,就可以对它会占用多少内存(尤其是大量内存)进行有根据的猜测。如果您真的想知道数据结构的确切大小,请查阅cpython资料;大多数内置类型是在中描述@H_419_5@Include/<type>object.h和实现的简单结构@H_419_5@Objects/<type>object.c。PyObject结构本身在中进行了描述@H_419_5@Include/object.h。请记住:它一直是指针。那些也占用空间。

python 2022/1/1 18:42:00 有269人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶