Python源码分析 :整数对象的实现-1

python中的对象分两种:可变对象与不可变对象。

intfloatstring,元组就是不可变对象;list,map及自定义对象就是可变对象。

好了,现在知道python中一切皆对象并且int为不可变对象,想像一下一个for循环:

for I in ragne(1,1000):

print I

就会出现不停地生成对象然后销毁对象。靠,这不是在烧CPU是在干什么。显然,python的发明者肯定不会做这样的蠢事。那么他是怎么完成的呢?

仔细想一下,如果一个int对象是不可变的,我们就可以重复利用了不是。对,python的发明者就是想到了重复利用:一个小整数池。在python初始化时就生成一个存放一定范围内整数的PyIntObject对象池,供编程人员随时调用。而且这个范围可以调整(当然,得重新编译python后才能生效)。下面看看,是如何从这个小整数池中取数字的:

PyObject *

PyInt_FromLong(long ival)

{

register PyIntObject *v;

/*采用了小整数池*/

#if NSMALLNEGINTS + NSMALLPOSINTS > 0

if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {

/*若在小整数池范围内*/

v = small_ints[ival + NSMALLNEGINTS];

。。。。

判断要求生成的整数是否落在小整数范围内,若是则返回(可能这个对象在其它地方也被使用了,这无妨啊,因为任何人都不能改变其中的整数信息)

好了,小整数你可以用这个池在O(1)的时间内返回,那么超过这个范围呢,难道还是用不停的malloc吗?肯定也不是,那么是?

其实这个思想其根本就是空间换时间,即事先生成好,用的时间只要时行简短的初始化就可以拿来使用(类似于静态内存分配)。python也干了这么件事。当缺少‘大’整数时,就生成一堆‘大’整数对象。啥时候这个整数堆使用完了,再生成一个。

这里使用了如何将一块内存格式化成 结构化的单链表,及如何进行妥协编程(使用ob_type作为结点的‘next’指针域)。

但有一个问题:由于整数堆是单链表串起来的,那么如果前面的某个堆里的整数对象释放后,岂不是永远无法再使用了,这和内存泄漏有什么区别?想知道怎么回事吗,且看下回分析!

发表评论