整数对象 PyIntObject
PyIntObject 是一个值不可变对象
定义
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
相应的与整数类型相对应的类型对象为PyInt_Type
PyTypeObject PyInt_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"int",
sizeof(PyIntObject),
0,
(destructor)int_dealloc, /* tp_dealloc */
(printfunc)int_print, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)int_compare, /* tp_compare */
(reprfunc)int_to_decimal_string, /* tp_repr */
&int_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)int_hash, /* tp_hash */
0, /* tp_call */
(reprfunc)int_to_decimal_string, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_INT_SUBCLASS, /* tp_flags */
int_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
int_methods, /* tp_methods */
0, /* tp_members */
int_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
int_new, /* tp_new */
};
Attribute | Operation |
---|---|
int_dealloc | PyIntObject 对象的析构操作 |
int_free | 对象的释放操作 |
int_repr | 转化为PyStringObject对象 |
int_hash | 获得hash值 |
int_print | 打印 |
int_compare | 比较 |
int_as_number | 数值操作集合 |
int_methods | 成员函数集合 |
其中含义
Attribute | Operation |
---|---|
int_dealloc | PyIntObject 对象的析构操作 |
int_free | 对象的释放操作 |
int_repr | 转化为PyStringObject对象 |
int_hash | 获得hash值 |
int_print | 打印 |
int_compare | 比较 |
int_as_number | 数值操作集合 |
int_methods | 成员函数集合 |
创建与维护
创建
在python的内部,python为这些内建的对象提供了特定的C API
创建一个PyIntObject
可以由下面三种方式:
PyObject *PyInt_FromLong(long ival)
PyObject* PyInt_FromString(char *s, char **pend, int base)
#ifdef Py_USING_UNICODE
PyObject*PyInt_FromUnicode(Py_UNICODE *s, int length, int base)
#endif
小整数
由于整数在程序中非常频繁的使用,尤其是小整数,那么为了确保效率,便不可能频繁的申请新内存来创建整数对象,不断的释放就内存。因此,为提高效率,python对小整数使用了内存池技术。
[intobject.c]
#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
(可以通过以上源码的方式来修改小整数的范围)
在上面代码中还定义了small_ints
来作为小整数的对象池
大整数
对于大整数,python运行环境提供了一块内存,来给这些大整数轮流使用
[intobject.c]
#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;
(上述代码显示了python通过单链表的方式来维护这块内存)
添加和删除
- 添加,创建PyIntObject对象
[intobject.c]
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
//为通用整数对象池申请新内存空间
//第一次运行时free_list为NULL,(已用完,也会为NULL)
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);
(void)PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
return (PyObject *) v;
}
关于内存池的分配fill_free_list
[intobject.c]
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);
Py_TYPE(q) = NULL;
return p + N_INTOBJECTS - 1;
}
(注意,这里使用了PyObject中的ob_type指针作为连接指针)
- 删除,释放PyIntObject对象
[intobject.c]
static void
int_dealloc(PyIntObject *v)
{
//检查对象是否是PyIntObject(避免对其派生类进行内存操作)
if (PyInt_CheckExact(v)) {
//是PyIntObject类型
Py_TYPE(v) = (struct _typeobject *)free_list;
free_list = v;
}
else
//不是PyIntObject类型,是其派生类
Py_TYPE(v)->tp_free((PyObject *)v);
}
(在释放时,将释放掉的对象内存加到了free_list链表,以备生成时重复使用)
- 小整数对象池的初始化
[intobject.c]
int
_PyInt_Init(void)
{
PyIntObject *v;
int ival;
// 小整数池是否被激活
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) {
if (!free_list && (free_list = fill_free_list()) == NULL)
return 0;
/* PyObject_New is inlined */
v = free_list;
free_list = (PyIntObject *)Py_TYPE(v);
(void)PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
small_ints[ival + NSMALLNEGINTS] = v;
}
#endif
return 1;
}
(上述代码显示,其实小整数内存池也是通过block_list
来管理的)
参考
《Python 源码剖析》