python对象内存模型

原文:Python的垃圾回收机制(二)之内存模型

1. Python对象内存模型

首先介绍一下Python对象的内存模型,如下图1所示:

这里写图片描述
图1. PyObject对象内存模型

上图可以看到,一个PyObject必须包含ob_refcntob_type这两个属性ob_refcnt是这个对象的引用计数,而ob_type则是指向_typeobject结构体的指针,它是Python内部的一种特殊对象,它是用来制定一个对象类型的类型对象,所以上图中它指向了一个PyTypeObject

在PyTypeObject中定义了大量的函数指针,这些函数指针最终都会指向某个函数,或者指向NULL。这些函数指针可以视为类型对象中所定义的操作,而这些操作直接决定着一个对象在运行时所表现出的行为。如list类内置的各种魔法方法(list.append(), list.sort()等)。

在Python中,对象机制的核心其实非常简单,一个是引用计数,一个是类型信息。

a). 定长对象(Fixed-sized)

我们再来看定长对象None, Int,List,其结构如下图2所示:

这里写图片描述
图2. None, Int, List对象内存模型

上图可以看到,None对象的内存模型是与PyObject一致的;而Int对象则是多了一个ob_ival,这个字段其实就是存储Int真实的value。

问题一:令人奇怪的是,在Python中,List其实是一个可变长的,类似于C++中的vector的数据结构,为什么它的内存模型是定长的呢?

其实它的内存模型的字段都是元数据(meta-data),而真正存放数组数据的是ob_item指向的一个数组。

问题二:在PyListObject对象中,有一个ob_size,而在最后为什么又有一个allocated,那么这两个变量之间的关系是什么呢?

其实,ob_sizeallocated都和PyListObject对象的内存管理有关,PyListObject所采用的内存管理策略和C++中的vector采取内存管理策略是一样的。在每一次需要申请内存的时候, PyListObject总会申请一大块内存,这是申请的总内存的大小记录在allocated中,而实际被使用了的内存的数量则记录在了ob_size中。

b). 变长对象(Variable-sized)

我们再来看看变长对象的内存模型,例如tuple,它的结构如下图3所示:

这里写图片描述
图3. tuple对象内存模型

上图就可以解释,为什么tuple在python中使用是一个定长的list,为什么在PyObject中却是变长对象了。

而string的内存模型如下图所示:

这里写图片描述
图4. string对象内存模型

在创建PyStringObject对象时,除了为PyString_Object申请内存,还有为字符数组内的元素申请额外的内存(绿色填充的字符数组内存)。然后将hash缓存值设为-1,将参数str指向的字符数组内的字符拷贝到PyStringObject所维护的空间中,在拷贝过程中,将字符数组最后的'\0'字符也拷贝了。

c). All is Object

上面讲述了很多python的基础数据类型,而这些基础类型(包括PyTypeObject)都是对象(All is Object)。每个对象至少包含了ob_refcntob_type两个字段,如果是32bit的操作系统,那么他们共是8个字节。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值