Python源码--整数对象(PyIntObject)的内存池
来源:互联网 发布:贵州省大数据云平台 编辑:程序博客网 时间:2024/05/22 08:00
【背景】
原文链接:http://blog.csdn.net/ordeder/article/details/25343633
Python整数对象是不可变对象,什么意思呢?例如执行如下python语句
>>>a = 1023
>>>a = 1024
>>>b = a
>>>c = 1024
>>>d = 195
>>>e = 195
python的整数对象结构为:
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
第一条命令执行后,python vm 创建了一个PyIntObject A,其中的ob_ival=1023记录了该整数对象的值,名字a引用该对象,即A 的 ob_refcnt=1。
当执行第二条语句的时候,python vm 又建立了新的PyIntObject B,其ob_ival值为1024.且名字a解引用AA的ob_refcnt-1变成0,系统将其回收。名字a引用对象B,B的ob_refcnt=1;
执行第三条语句,名字b引用名字a引用的对象,故而B的ob_refcnt+1,即为2;
第四条语句:c引用了不同于B的另一个整数对象
第五条语句:d引用了小整数对象195
第六条语句: e和d引用的是同一个对象,及小整数对象
p.s. 小整数的范围为[-5,257)
在python中的PyIntObject对象ob_ival内容是不可变的。
【Python中整数对象的存储优化】
由于python中的整数对象记录的整数值是不可变的,所以在名字a的值不断变化的过程中,就就涉及到了多次对象的创建和销毁。所以python为整数对象申请空间进行了两种优化:优化1:为通用整数对象存储池
优化2:为小整数对象构建特殊的缓冲
PyIntObject分为小整数对象[-5~257)及大整数对象。小整数对象在py启动过程中初始化,从而实现小整数对象的缓存,缓冲中的小整数对象在py运行期间不会被销毁。 大整数对象需要程序员动态申请,对象在运行过程中根据ob_refcnt引用计数确定是否销毁(计数为0)。
其次,py为了优化整数对象的申请工作,为大整数对象引入了缓冲池的概念。为何引入缓冲池?我的理解是:对于系统来说,alloc一个PyIntObject对象,需要一次系统调用,为了避免每次创建对象都去调用alloc,便引入整数缓冲池的概念。
【小整数缓冲】
看着名字感觉挺神奇,其实就是在vm启动的时候预先将[-5~257)这些整数构建相应的整数对象。这些整数
对象的构建所在的内存空间同样是在:通用整数对象的缓冲池。只不过这些个小整数对象的ob_refcnt不会改变
且永远>0,所以在vm运行过程中不会被销毁,所以起到了缓冲的作用。
【通用整数对象的缓冲池】
为了减少alloc系统调用申请空间,内存池一次性申请的空间不是当个PyIntObject大小,而是一个以PyIntBlock块为结构的大小的空间,每个PyIntBlock块容纳了n个PyIntObject对象。内存池的基本数据结构如下:
#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject))struct _intblock { struct _intblock *next; PyIntObject objects[N_INTOBJECTS];};typedef struct _intblock PyIntBlock;static PyIntBlock *block_list = NULL;static PyIntObject *free_list = NULL;系统在启动的时候,PyIntBlock *block_list为空的,在运行过程中,如果需要创建整数对象,系统会先判定block_list是否有空闲的空间供创建对象,通过fill_free_list()函数从缓冲池中获取可用的PyIntObject。
如果free_list有空闲的PyIntObject可用,则直接在缓冲池中获取该空闲空间,你懂得。
如果没得,系统将通过alloc申请一个PyIntBlock挂入block_list中,同时将该块分为N_INTOBJECTS整数对象PyIntObject挂入到free_list中。
1. fill_free_list()的函数实现
static PyIntObject * fill_free_list(void){ PyIntObject *p, *q; /* Python's object allocator isn't appropriate for large blocks. */ p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock)); if (p == NULL) return (PyIntObject *) PyErr_NoMemory(); ((PyIntBlock *)p)->next = block_list; block_list = (PyIntBlock *)p; /* Link the int objects together, from rear to front, then return the address of the last int object in the block. */ p = &((PyIntBlock *)p)->objects[0]; q = p + N_INTOBJECTS; while (--q > p) Py_TYPE(q) = (struct _typeobject *)(q-1); //[1] Py_TYPE(q) = NULL; return p + N_INTOBJECTS - 1;}说明[1]
py将PyIntObject->ob_type作为free_list的临时next指针,使用了指针强制转换,虽然破坏了指针的安全原则,但是重用了>ob_type内存空间,不失为一种好方法!下图描绘了两个PyIntBlock构成的通用整数缓冲池:
2. 其余两个构建和删除整数对象相关函数:
//构建intobjPyObject * PyInt_FromLong(long ival){ register PyIntObject *v;#if NSMALLNEGINTS + NSMALLPOSINTS > 0 if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { v = small_ints[ival + NSMALLNEGINTS]; Py_INCREF(v);#ifdef COUNT_ALLOCS if (ival >= 0) quick_int_allocs++; else quick_neg_int_allocs++;#endif return (PyObject *) v; }#endif if (free_list == NULL) { //[1] if ((free_list = fill_free_list()) == NULL) return NULL; } /* Inline PyObject_New */ v = free_list; //[2] free_list = (PyIntObject *)Py_TYPE(v); PyObject_INIT(v, &PyInt_Type); v->ob_ival = ival; return (PyObject *) v;}[1]缓冲池的空闲链表为空,通过fill_free_list()去申请新的PyIntBlock[2](PyIntObject *)Py_TYPE(v)相当于是PyIntObject在free_list中的next指针。//删除intobjstatic void int_dealloc(PyIntObject *v){ if (PyInt_CheckExact(v)) { //[1] Py_TYPE(v) = (struct _typeobject *)free_list; free_list = v; } else //[2] Py_TYPE(v)->tp_free((PyObject *)v);}[1] 判定如果v的引用计数为1(经过本次解引用变为0),则将该PyIntObject空间加入到缓冲池的空闲队列,以便重用[2]引用计数>2 将该对象引用计数减1
- Python源码--整数对象(PyIntObject)的内存池
- [笔记]Python的整数对象:PyIntObject
- [Python源码学习]之整数类型PyIntObject
- 对PyIntObject的认识(对象池)
- Python内部机制-PyIntObject对象
- Python源码学习笔记 2 整数对象
- 《python源码剖析》笔记 python中的整数对象
- Python源码剖析笔记2-Python整数对象
- Python源码剖析(02 Python中的整数对象)
- Python中小整数对象池和大整数对象池
- Python源码剖析[3] —— 整数对象(1)
- Python源码剖析[4] —— 整数对象(2)
- Python源码剖析[5] —— 整数对象(3)
- 《Python源码剖析》阅读笔记:第二章-整数对象
- Python中整数对象的实现
- 深入 Python 整数对象的实现
- Python整数对象相关
- 有趣的python:关于python中的整数类型对象
- iOS第三方开源库的吐槽和备忘
- UVA ShellSort
- hdu 2476 String painter 区间dp
- 电池容量足够低如何触发自动关机(Riogrande platform&Qualcom platform)
- 几个PHP读取整个文件的函数readfile()、fpassthru()和file()
- Python源码--整数对象(PyIntObject)的内存池
- CRectTracker类的使用
- 有关于面试常遇到的问题回答,以及解决方案。
- 集合体系框架基础总结
- 驱动Lenovo 5110
- vim安装中文帮助手册
- JSON
- java性能优化之java web项目性能优化(一)
- VMware Workstation虚拟机中体验Mac OS X 10.9 Mavericks