理解Python中的整数对象的实现,有助于我们了解Python的对象系统。在此记下这几天的阅读内容。
PyIntObject是一个结构体,由一个PyObjec_HEAD和int ob_ival组成,如下:
typedef struct { PyObject_HEAD long ob_ival; } PyIntObject;
而PyObject_HEAD这个结构体中又有两个字段:int ref引用计数器,struct _typeobject * ob_type表示类型的指针。
Python整数类型分为小整数和大整数,对于频繁使用的小整数,采用引用计数方式,相同的值共享同一块内存,是在python初始化时就分配好了的。
一般为-5~257,可以自己调整。对于这其中的数, 完全缓存。
#ifndef NSMALLPOSINTS #define NSMALLPOSINTS 257 #endif #ifndef NSMALLNEGINTS #define NSMALLNEGINTS 5 #endif #if NSMALLNEGINTS + NSMALLPOSINTS > 0 /* References to small integers are saved in this array so that they can be shared. The integers that are saved are those in the range -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). */ static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; #endif
对于大整数,则是使用PyIntBlock结构,实现单相列表,将内存链接起来,使用的时候,就从free_list里取出一块。
#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;
当然,del一个大整数对象的时候,并不是将内存归还给系统,而是加入到自由链表中。
最后,我们来看一看整数对象的创建:
PyObject * 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) { if ((free_list = fill_free_list()) == NULL) return NULL; } /* Inline PyObject_New */ v = free_list; free_list = (PyIntObject *)Py_TYPE(v); PyObject_INIT(v, &PyInt_Type); v->ob_ival = ival; return (PyObject *) v; }