-
PyStringObject对象
typedef struct { PyObject_VAR_HEAD long ob_shash; int ob_sstate; char ob_sval[1]; } PyStringObject;
头部保存一个ob_size,表示字符串在内存中的具体长度,字符串由ob_sval指针指向,但是,字符串的最后一位也一定是’\0’结束,由于有ob_size的标记,允许字符串中间也有’\0’字符的存在。
-
字符串的类型对象中,tp_itemsize设置为sizeof(char),这个值表示变长对象中每个元素单位的长度,每一个python中的变长对象(string、list等),都需要在对应的类型对象中设置tp_itemsize的值。tp_itemsize和ob_size共同决定了一个对象需要在内存中实际占用的空间大小。
-
对于空字符串,python会返回其内部的nullstring对象,避免每次都创建,这个对象相当于是共享的。
-
Intern机制。为了避免每次为相同的字符串开创新对象,可以利用Intern机制来实现。相当于创建时会先查找是否有使用了Intern机制创建的对象,包含的字符串和待创建的一样,如果存在,则直接返回该对象的引用,而不用再次创建一个全新的对象。
-
interned的实现,实际上是维护了一个map<PyObject*, PyObject*>的字典集合,key,value都是那个采用Interned机制的Py对象指针,如果在这个map中找到一个对象的字符串内容和待创建的一致,则直接把待创建的指针指向这个map的value。加入Map时,按照py的引用计数规则,对应的对象引用计数会先+1,相当于这个对象引用+2了,这样的话,这种对象实际不可能出现引用为0的情况,所有,对于加入到Interned中的对象,会在加入完毕后执行引用计数-2的操作。
-
对于单个字符的,也有一个静态缓冲区,类似PyIntObject对小整数的处理。
-
PyListObject类似于c++中的vector
-
结构定义:
typedef struct { PyObject_VAR_HEAD PyObject **ob_item; int allocated; } PyListObject;
一次分配的内存是大于现实需要的内存,类似vector的内存分配策略。
0 <= ob_size <= allocated;
len(list) == ob_size -
append的元素会放在ob_size位置上,所以内部元素的内存空间不一定连续,但是逻辑上是连续的
-
PyList的对象缓冲池。 在每个PyList被销毁的那会,会检测free_list这个缓冲池是否满了,如果没满,则会把当前这个待销毁的对象放入这个缓冲池中。当然,这个List内部的元素item都是要被free掉内存的,不然就是一堆野指针了。只是这个对象的内存空间会被缓存下来,避免下次的再次申请内存导致额外的消耗。
-
PyDictObject底层采用hash_table来存储,hash冲突利用开放地址法来解决(lookdict方法来搜索元素)。
-
dict里面每个pair对都是一个PyDictEntry
typedef struct { long me_hash; /* cached hash code of me_key */ PyObject *me_key; PyObject *me_value; } PyDictEntry;
每个dict内部都有一个PyDictEntry的小规模数组(默认8),当dict的size小于8时,内部标识的ma_table指针就指向这个小数组,如果大于8,则申请一块大内存,ma_table指向那块内存。me_key有三种状态,dummy、unused和实际有效使用的active。删除元素后会变成dummy状态,freeslot指针会指向该位置,freeslot在下次插入新元素时会使用到。
-
搜索时根据hash值查找,如果查到的key和待搜索的不同,则根据lookdict二次探测。
-
dict每次的插入,会调用PyDict_SetItem,在这里面会先计算hash值,hash = PyObject_Hash(PyObject*)。在最后,会根据装载率来决定当前ma_table指向的内存是否需要扩容,因为装载率高了,hash冲突的概率就会加大。
-
PyDict使用的缓冲池技术和Int这些类似,都是在一个Object销毁时加入到缓冲池中。
python源码剖析-笔记2
最新推荐文章于 2024-09-16 21:12:47 发布
本文深入探讨Python中的PyStringObject结构,包括ob_size和ob_sval的用法,解释了空字符串的优化处理和Intern机制。此外,还介绍了PyListObject的内存分配策略、对象缓冲池以及PyDictObject的哈希表实现,包括开放地址法解决冲突和装载率对扩容的影响。
摘要由CSDN通过智能技术生成