Python源代码--整数对象(PyIntObject)的内存池
【背景】
原文链接: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. 其余两个构建和删除整数对象相关函数:
//构建intobj
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) { //[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指针。 //删除intobj
static 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中小整数对象池和大整数对象池
1. 小整数对象池 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间. Python 对小整数的定义是 [-5, 256] 这些整数对象是提 ...
- python中小整数对象池及intern机制
小整数对象池: Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁 Python 对小整数的定义是 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收,所有位于这个范围 ...
- linux内存源码分析 - 内存池
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 内存池是用于预先申请一些内存用于备用,当系统内存不足无法从伙伴系统和slab中获取内存时,会从内存池中获取预留的 ...
- Boost内存池使用与测试
目录 Boost内存池使用与测试 什么是内存池 内存池的应用场景 安装 内存池的特征 无内存泄露 申请的内存数组没有被填充 任何数组内存块的位置都和使用operator new[]分配的内存块位置一致 ...
- Linux设备驱动程序 之 内存池
内核中有些地方的内存分配是不允许失败的,为了确保这种情况下的成功分配,内核开发者建立了一种称为内存池的抽象:内存池其实就是某种形式的后备高速缓存,它试图始终保存空闲的内存,以便在紧急状态下使用: me ...
- python tips:小整数对象池与字符串intern
本文为is同一性运算符的详细解释.is用于判断两个对象是否为同一个对象,具体来说是两个对象在内存中的位置是否相同. python为了提高效率,节省内存,在实现上大量使用了缓冲池技术和字符串intern ...
- Python 源码剖析(二)【整数对象】
二.整数对象 1.PyIntObject 2.PyIntObject 对象的创建和维护 3.Hack PyIntObject 1.PyIntObject PyIntObject的定义: [intobj ...
- python 小整数池 和intern 【整理】
小整数对象池 (在python内置了) 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间. Python对小整数的定义是[-5,257]这些整 ...
- [python 源码]整数对象的创建和维护
刚开始学python时候,发现一个很迷惑的现象,一直到看了源码后才知道了: >>> a=6 >>> b=6 >>> a is b True 想用同 ...
随机推荐
- 【LeetCode】Path Sum(路径总和)
这道题是LeetCode里的第112道题.是我在学数据结构——二叉树的时候碰见的题.题目要求: 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和 ...
- django 常见过滤器
一.形式:小写 {{ name | lower }} 二.过滤器是可以嵌套的,字符串经过三个过滤器,第一个过滤器转换为小写,第二个过滤器输出首字母,第三个过滤器将首字母转换成大写 标签 {{ st ...
- luogu3755 [CQOI2017]老C的任务
扫描线水题. #include <algorithm> #include <iostream> #include <cstdio> using namespace ...
- nw.js学习地址
http://blog.sina.com.cn/s/blog_600e56a60102vqj2.html https://github.com/nwjs/nw.js/wiki/Manifest-For ...
- 一、harbor部署之centos7的基本配置
1 最小安装centos7 ...安装省略... centos7最小化安装后没ifconfig命令,用 ip addr 命令查看网络信息. 2 配置网络 1.cd /etc/sysconfig/net ...
- centos 7 安装vmware 12
1.下载VMware 衔接地址 http://www.vmware.com/products/workstation/workstation-evaluation ,下载Linux版本的VMware. ...
- jenkins+jacoco+ant+apache集成统计web端功能测试覆盖率
一.覆盖率定义 作为一个测试人员,保证产品的软件质量是其工作首要目标,为了这个目标,测试人员常常会通过很多手段或工具来加以保证,覆盖率就是其中一环比较重要的环节. 我们通常会将测试覆盖率分为两个部分, ...
- 【leetcode 字符串】466. Count The Repetitions
https://leetcode.com/problems/count-the-repetitions/description/ 找循环节 https://www.cnblogs.com/grandy ...
- cf615D Multipliers
Ayrat has number n, represented as it's prime factorization pi of size m, i.e. n = p1·p2·...·pm. Ayr ...
- sublime text3安装angularjs插件
sublime能够支持AngularJS开发那绝对是一件很爽的事情.下面我一步步讲解如何为sublime安装AngularJS插件. 首先提供一个破解版的sublime text 3的下载地址:htt ...