python长整数实现_Python 整数对象的实现

本文详细介绍了Python中整数对象的管理方式,包括小整数对象池的范围([-5, 257))以及大整数对象的内存扩展策略。通过修改Python源代码,展示了如何查看整数对象的引用次数、内存地址和空闲内存管理。此外,还揭示了小整数对象的复用机制和大整数对象在内存中的分配与回收过程。
摘要由CSDN通过智能技术生成

Python 的内建对象存放在源代码的Objects目录下。

intobject.c用于整数对象

在 Python 中,整数分为小整数对象和大整数对象

小整数对象

由于数值较小的整数对象在内存中会很频繁地使用,如果每次都向内存申请空间、请求释放,会严重影响 Python 的性能。好在 整数对象 属于不可变对象,可以被共享而不会被修改导致问题,所以为 小整数对象 划定一个范围,即小整数对象池,在Python运行时初始化并创建范围内的所有整数,这个范围内的 整数对象是被共享的,即一次创建,多次共享引用。

那么这个范围是多少呢?从源文件中可以看到,而且,用户可以自行调整,只是每次都要在源文件中修改,而后进行编译、安装。

小整数池的范围:

#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];

从源代码可以看出

define NSMALLPOSINTS 257,范围的右边界

define NSMALLNEGINTS 5,范围的左边界

-NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive),[-5, 257)

大整数对象

但是,整数对象很多,不一定都是小整数对象,又不能将所有整数对象都放入内存。于是,Python 提供了一个可扩展的内存空间,称为通用整数对象池,谁需要用就给谁用,这样免去了申请空间,又能提高一些效率。

这个空间是一个PyIntBlock结构,是用一个单向列表连接一串内存(block),这个列表由block_list维护,而每个 block 维护一个 整数对象数组(Objects),用于存放被缓存的整数对象。block_list的内容是最新创建的 block。

小整数对象池 也在block_list上。

Python 使用一个单向链表管理全部 block 的 objects 中的所有空闲内存,由free_list指出下一个可用的空闲内存。如果当前没有空闲内存,free_list为NULL,会创建新的内存。

当整数对象的引用计数变为0,会销毁对象,但并不会释放空闲出来的内存,即将内存交还系统,而是重新加入free_list。

hack

使用Xcode修改打印整数对象的方法

原始文件

/* ARGSUSED */

static int

int_print(PyIntObject *v, FILE *fp, int flags)

/* flags -- not used but required by interface */

{

long int_val = v->ob_ival;

Py_BEGIN_ALLOW_THREADS

fprintf(fp, "%ld", int_val);

Py_END_ALLOW_THREADS

return 0;

}

修改后,可以打印部分小整数地址池中,整数对象的引用次数、所在内存地址、下一个可用的空闲内存地址

/* ARGSUSED */

static int values[10];

static int refcounts[10];

static int

int_print(PyIntObject *v, FILE *fp, int flags)

/* flags -- not used but required by interface */

{

PyIntObject* intObjectPtr;

PyIntBlock *p = block_list;

PyIntBlock *last = NULL;

int count = 0;

int i;

while(p != NULL)

{

++count;

last = p;

p = p->next;

}

intObjectPtr = last->objects;

intObjectPtr += N_INTOBJECTS - 1;

printf(" address @%p\n", v);

for(i = 0; i < 10; ++i, -- intObjectPtr)

{

values[i] = intObjectPtr -> ob_ival;

refcounts[i] = intObjectPtr -> ob_refcnt;

}

printf(" value : ");

for(i = 0; i < 8; ++i)

{

printf("%d\t", values[i]);

}

printf("\n");

printf(" refcnt : ");

for(i = 0; i < 8; ++i)

{

printf("%d\t", refcounts[i]);

}

printf("\n");

printf(" block_list count : %d\n", count);

printf(" free_list : %p\n", free_list);

return 0;

/* long int_val = v->ob_ival;

Py_BEGIN_ALLOW_THREADS

fprintf(fp, "%ld", int_val);

Py_END_ALLOW_THREADS

return 0;*/

}

保存并编译、安装,运行修改后的 Python

Python 2.6.9 (unknown, Nov 1 2015, 20:22:05)

[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.1.76)] on darwin

Type "help", "copyright", "credits" or "license" for more information.

>>>

>>> i = -9999

>>> i

address @0x7fe412f16470 # -9999 所在的内存地址

value : -5 -4 -3 -2 -1 0 1 2 # 能够显示的 -5 ~ 2

refcnt : 1 1 1 1 35 105 64 41 # 引用计数器,可以看到,小整数已经被Python自身使用了多次

block_list count : 8 # block 数量

free_list : 0x7fe412f16488 # 下一个可用的空闲内存地址

>>>

>>> a = -258

>>> a

address @0x7fe412f16488 # -258 的内存地址,是上面`free_list`指出的空闲内存

value : -5 -4 -3 -2 -1 0 1 2

refcnt : 1 1 1 1 35 105 64 41

block_list count : 8

free_list : 0x7fe412f164a0 # 新的空闲内存地址

>>> b = -258

>>> b

address @0x7fe412f164a0 # 上一个的空闲内存地址,可以看出,对于多次创建的大整数对象,即使值一样,也是不同的内存地址

value : -5 -4 -3 -2 -1 0 1 2

refcnt : 1 1 1 1 35 105 64 41

block_list count : 8

free_list : 0x7fe412f164b8

>>> del b # 释放 b 的内存空间

>>> a

address @0x7fe412f16488

value : -5 -4 -3 -2 -1 0 1 2

refcnt : 1 1 1 1 35 105 64 41

block_list count : 8

free_list : 0x7fe412f164a0 # 删除 b 后,新的空闲内存重新加入`free_list`,没有归还给系统

>>> c1 = -5 # 属于小整数对象池

>>> c1

address @0x7fe412f033d8

value : -5 -4 -3 -2 -1 0 1 2

refcnt : 5 1 1 1 35 105 64 41 # -5 引用此时为 5

block_list count : 8

free_list : 0x7fe412f164b8

>>> c2 = -5 # 同上

>>> c2

address @0x7fe412f033d8 # 两次创建的相同小整数对象,指向了相同的内存地址

value : -5 -4 -3 -2 -1 0 1 2

refcnt : 6 1 1 1 35 105 64 41 # -5 的引用次数加一,变为 6

block_list count : 8

free_list : 0x7fe412f164b8

>>>

整数对象的说明文件内置在源代码中:

PyDoc_STRVAR(int_doc,

"int(x[, base]) -> integer\n\

\n\

Convert a string or number to an integer, if possible. A floating point\n\

argument will be truncated towards zero (this does not include a string\n\

representation of a floating point number!) When converting a string, use\n\

the optional base. It is an error to supply a base when converting a\n\

non-string. If base is zero, the proper base is guessed based on the\n\

string content. If the argument is outside the integer range a\n\

long object will be returned instead.");

int_doc就是整数对象的__doc__属性

参考资料

《Python 源码剖析》第二章:整数对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值