Python 源码剖析(二)【整数对象】
二、整数对象
1、PyIntObject
2、PyIntObject 对象的创建和维护
3、Hack PyIntObject
1、PyIntObject
PyIntObject的定义:
[intobject.h]
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
其类型对象为PyInt_Type:
[intobject.c]
PyTypeObject PyInt_Type = {
PyObject_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_repr, /* 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_repr, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_BASETYPE, /* 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 */
0, /* 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 */
(freefunc)int_free, /* tp_free */
};
可见PyInt_Type保存着PyIntObject的元信息,包括这些操作:
int_dealloc |
删除PyIntObject对象 |
int_free |
删除PyIntObject对象 |
int_repr |
转化成PyString对象 |
int_hash |
获得HASH值 |
int_print |
打印PyIntObject对象 |
int_compare |
比较操作 |
int_as_number |
数值操作 |
int_methods |
成员函数 |
比较操作代码,其实就是将包装的long进行比较:
[intobject.c]
static int int_compare(PyIntObject *v, PyIntObject *w)
{
register long i = v->ob_ival;
register long j = w->ob_ival;
return (i < j) ? -1 : (i > j) ? 1 : 0;
}
注意int_as_number,其实是一个PyNumberMethods结构体:
[intobject.c]
static PyNumberMethods int_as_number = {
(binaryfunc)int_add, /*nb_add*/
(binaryfunc)int_sub, /*nb_subtract*/
(binaryfunc)int_mul, /*nb_multiply*/
……
(binaryfunc)int_div, /* nb_floor_divide */
int_true_divide, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
};
PyNumberMethods定义了38个数值操作,如加法:
[intobject.h]
/* Macro, trading safety for speed */
#define PyInt_AS_LONG(op) (((PyIntObject *)(op))->ob_ival)
[intobject.c]
#define CONVERT_TO_LONG(obj, lng) \
if (PyInt_Check(obj)) { \
lng = PyInt_AS_LONG(obj); \
} \
else { \
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
}
static PyObject *
int_add(PyIntObject *v, PyIntObject *w)
{
register long a, b, x;
CONVERT_TO_LONG(v, a);
CONVERT_TO_LONG(w, b);
x = a + b;
if ((x^a) >= 0 || (x^b) >= 0)
return PyInt_FromLong(x);
return PyLong_Type.tp_as_number->nb_add((PyObject *)v, (PyObject *)w);
}
如果没有溢出,就返回一个新的PyIntObject,否则返回一个PyLongObject。
2、PyIntObject 对象的创建和维护
2.1、Python创建的途径
有三种途径可获得一个PyIntObject对象:
PyObject *PyInt_FromLong(long ival)PyObject* PyInt_FromString(char *s, char **pend, int base)#ifdef Py_USING_UNICODEPyObject*PyInt_FromUnicode(Py_UNICODE *s, int length, int base)#endif
其中PyInt_FromString时先转成浮点数再调用PyInt_FromLong:
[intobject.c]PyObject* PyInt_FromString(char *s, char **pend, int base){char *end;long x;......//convert string to longif (base == 0 && s[0] == '0'){x = (long) PyOS_strtoul(s, &end, base);}elsex = PyOS_strtol(s, &end, base);......return PyInt_FromLong(x);}
2.2、小整数对象
频繁申请、释放空间会降低运行效率、产生系统堆内存碎片,影响python性能。因此对于经常使用的整数,python使用对象池技术,并将小整数(对象池保存范围)定位[-5,100):
[intobject.c]
#ifndef NSMALLPOSINTS#define NSMALLPOSINTS 100#endif#ifndef NSMALLNEGINTS#define NSMALLNEGINTS 5#endif#if NSMALLNEGINTS + NSMALLPOSINTS > 0/* References to small integers are saved in this array so that theycan 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
2.3、大整数对象
对于大整数,pyhton则是使用内存池,提供一个free_list保存,谁需要保存谁:
[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;
PyIntBlock的单向列表通过block_list维护,而这些block中的PyIntObject的列表中可以被使用的内存通过free_list来维护(一个block可放82个PyIntObject)。
2.4、添加和删除
看一下产生PyIntObject:
[intobject.c]PyObject* PyInt_FromLong(long ival){register PyIntObject *v;#if NSMALLNEGINTS + NSMALLPOSINTS > 0if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {v = small_ints[ival + NSMALLNEGINTS];Py_INCREF(v);#ifdef COUNT_ALLOCSif (ival >= 0)quick_int_allocs++;elsequick_neg_int_allocs++;#endifreturn (PyObject *) v;}#endifif (free_list == NULL) {if ((free_list = fill_free_list()) == NULL)return NULL;}/* Inline PyObject_New */v = free_list;free_list = (PyIntObject *)v->ob_type;PyObject_INIT(v, &PyInt_Type);v->ob_ival = ival;return (PyObject *) v;}
先判断是否为小整数,是的话返回对象池中的小整数;否则转向block_list,调用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 returnthe address of the last int object in the block. */p = &((PyIntBlock *)p)->objects[0];q = p + N_INTOBJECTS;while (--q > p)q->ob_type = (struct _typeobject *)(q-1);q->ob_type = NULL;return p + N_INTOBJECTS - 1;}
当一个block没被填满时,不会再调用fill_free_list申请新空间,free_list指向可用空间,block_list指向最新创建的PyIntBlock对象。
注意,但某个对象被删除时,free_list会指向该空间,不会造成空间浪费:
[intobject.c]static void int_dealloc(PyIntObject *v){if (PyInt_CheckExact(v)) {v->ob_type = (struct _typeobject *)free_list;free_list = v;}elsev->ob_type->tp_free((PyObject *)v);}
2.5、小整数对象池的初始化
小整数对象池small_ints初始化 _PyInt_Init:
[intobject.c]int _PyInt_Init(void){PyIntObject *v;int ival;#if NSMALLNEGINTS + NSMALLPOSINTS > 0for (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 *)v->ob_type;PyObject_INIT(v, &PyInt_Type);v->ob_ival = ival;small_ints[ival + NSMALLNEGINTS] = v;}#endifreturn 1;}
3、Hack PyIntObject
修改int_print源码查看block_list、free_list、小整数缓冲池信息:
static int int_print(PyIntObject *v, FILE *fp, int flags)
{
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);
printf("********** value\trefCount **********\n");
for(i = 0; i < 10; ++i, --intObjectPtr)
{
printf("%d\t\t%d\n", intObjectPtr->ob_ival, intObjectPtr->ob_refcnt);
}
printf("block_list count : %d\n", count);
printf("free_list : %p\n\n", free_list);
return 0;
}
有兴趣的可以试一下。
Python 源码剖析(二)【整数对象】的更多相关文章
- 《Python 源码剖析》之对象
py一切皆对象的实现 Python中对象分为两类: 定长(int等), 非定长(list/dict等) 所有对象都有一些相同的东西, 源码中定义为PyObject和PyVarObject, 两个定义都 ...
- Python源码剖析——01内建对象
<Python源码剖析>笔记 第一章:对象初识 对象是Python中的核心概念,面向对象中的"类"和"对象"在Python中的概念都为对象,具体分为 ...
- Python 源码剖析(一)【python对象】
处于研究python内存释放问题,在阅读部分python源码,顺便记录下所得.(基于<python源码剖析>(v2.4.1)与 python源码(v2.7.6)) 先列下总结: ...
- Python开发【源码剖析】 List对象
前言 本文探讨的Python版本为2.7.16,可从官网上下载,把压缩包Python-2.7.16.tgz解压到本地即可 需要基本C语言的知识(要看的懂) PyListObject对象 PyListO ...
- Python源码剖析——02虚拟机
<Python源码剖析>笔记 第七章:编译结果 1.大概过程 运行一个Python程序会经历以下几个步骤: 由解释器对源文件(.py)进行编译,得到字节码(.pyc文件) 然后由虚拟机按照 ...
- python源码剖析学习记录-01
学习<Python源码剖析-深度探索动态语言核心技术>教程 Python总体架构,运行流程 File Group: 1.Core Modules 内部模块,例如:imp ...
- Python源码剖析|百度网盘免费下载|Python新手入门|Python新手学习资料
百度网盘免费下载:Python源码剖析|新手免费领取下载 提取码:g78z 目录 · · · · · · 第0章 Python源码剖析——编译Python0.1 Python总体架构0.2 Pyth ...
- Python 源码剖析 目录
Python 源码剖析 作者: 陈儒 阅读者:春生 版本:python2.5 版本 本博客园的博客记录我会适当改成Python3版本 阅读 Python 源码剖析 对读者知识储备 1.C语言基础知识, ...
- [Python源码剖析]获取Python小整数集合范围
#!/usr/bin/env python #-*- coding=utf-8 -*- small_ints = dict() for i in range(-10000,10000): small_ ...
- Python 源码剖析(六)【内存管理机制】
六.内存管理机制 1.内存管理架构 2.小块空间的内存池 3.循环引用的垃圾收集 4.python中的垃圾收集 1.内存管理架构 Python内存管理机制有两套实现,由编译符号PYMALLOC_DEB ...
随机推荐
- Web服务器、Web容器、Application服务器、反向代理服务器的区别与联系
在Web开发中,经常会听到Web服务器(Web Server).Web容器(Web Container).应用服务器(Application Server).反向代理服务器(Reverse Proxy ...
- springboot+websocket+sockjs进行消息推送【基于STOMP协议】
springboot+websocket+sockjs进行消息推送[基于STOMP协议] WebSocket是在HTML5基础上单个TCP连接上进行全双工通讯的协议,只要浏览器和服务器进行一次握手,就 ...
- 聊聊WS-Federation(test)
本文来自网易云社区 单点登录(Single Sign On),简称为 SSO,目前已经被大家所熟知.简单的说, 就是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. 举例: 我们 ...
- Spring学习记录-Java 11运行eureka-server报javax.xml.bind.JAXBContext not present错
在pom.xml加入依赖就行 <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId&g ...
- 「日常温习」Hungary算法解决二分图相关问题
前言 二分图的重点在于建模.以下的题目大家可以清晰的看出来这一点.代码相似度很高,但是思路基本上是各不相同. 题目 HDU 1179 Ollivanders: Makers of Fine Wands ...
- Jmeter断言、参数化及集合点
JMeter---QPS(Query Per Second) QPS为每秒查询率.是一台查询服务器每秒能够处理的查询次数,在因特网上,作为域名系统服务器的性能经常用每秒查询率来衡量.步骤:1.添加线程 ...
- C#-返回相对时间函数
在公司一直做前端,经理叫我写一个后端函数,要求是: 参数:DateTime--传入任意时间类型返回:string --返回传入参数时间与当前时间的相对时间字符串,如:3天前,1小时前,5分钟前. 注意 ...
- java实现遍历一个字符串的每一个字母(总结)
基础:牢记字符串操作的各种方法: String s = "aaaljlfeakdsflkjsadjaefdsafhaasdasd"; // 出现次数 int num = ...
- 【jmeter进阶之逻辑控制器】
jmeter进阶之逻辑控制器 转载 https://www.cnblogs.com/malinalian/p/10491946.html 常用的逻辑控制器 1,循环控制器:可以设置该控制器内 ...
- FastJson 序列化与反序列化一些说明
最近所属的组需要对接一些征信结构,就涉及到很多中的数据格式,而springmvc中使用的是jackson作为@ResponseBody的依赖jar 但是个人认为fastkson的性能要高于jackso ...