1.PyListObject对象的定义
typedef struct {
PyObject_VAR_HEAD
PyObject **ob_item; //指向存储列表对象指针数组的首地址
int allocated; //列表可以容纳的元素数目,注意这个和ob_size不同。ob_size表示已有元素数目,allocated表示能容纳的最多元素数目
} PyListObject;
说明:PyListObject和PyStringObject一样,都是变长对象,因此都有头PyObject_VAR_HEAD, 不同点是,PyStringObject是不可变对象,一旦创建,字符串内容不可改变;PyListObject则不同,可以再运行过程中动态删除、修改或新增元素。注意ob_size和allocated的关系:0 <= ob_size <= allocated
2.内存管理策略
每次申请内存是,PyListObject对象会申请一大块内存,而不是有多少元素申请多少元素,申请的总大小存储在allocated中。这样做是为了提高效率
3.修改、插入及删除操作
修改操作最简单,直接定位到相应位置替换掉对应位置的对象指针即可。如a = 100, ls[2] = a, 实际操作:(ls->ob_item + 2) = &a
插入操作:
对应两种操作,ls.insert(3, 'new value'); ls.append('new value'),这两个函数操作流程几乎相同
step1: 检查ls->ob_size和ls->allocated的关系,判断是否需要重新分配内存,如果ob_size < allocated,则无需重新分配内存,转step3,否则转step2重新分配内存(这一步并不完全,实际上还会检查如果allocated> 2*ob_size,也会重新分配内存,目的是释放过多的空闲内存)
step2:重新分配内存, 注意这步需要重新申请内存空间,然后将元ob_item的数据拷贝到新申请的空间
step3:在相应位置插入元素,其后所有元素需要往后移动.(这和C++中的Vector类似,插入操作效率较低)
删除操作:
删除操作将被删除对象对应的指针删除之后,其后的所有指针都要向前移动,和C++中的Vector类似,删除效率较低
注意:
删除操作可以删除单个元素,也可以删除片段,如del ls[1]; del ls[1 : 3]
替换也可以替换一个片段, 如ls[2:4] = [1,3,4,5],这个操作实际上是通过内存拷贝来实现
4.PyListObject缓冲池
Python系统会为List对象维护一个默认大小为80的对象缓冲池,每次创建新的List对象时,系统会坚持缓冲池中有没有空余空间,若有,则直接使用,重新围棋分配ob_item的空间,否则重新创建List对象。
该缓冲池初大小为0,在销毁List对象时会被分配空间。具体如下:
当销毁某List对象时,实际上分两步。第一步先销毁List维护的元素空间,即ob_item指向的内存空间,然后销毁List本身。当销毁完ob_item对应的空间之后,系统会检查缓冲池大小是否小于80,若小于80,系统不会真正销毁List对象本身,而是将其挂载到List缓冲区等待下次使用。