当前位置: 首页 > news >正文

Python源码剖析1-整数对象PyIntObject

1、PyIntObject 对象

[intobject.h]
typedef struct {
	PyObject_HEAD
    long ob_ival;
} PyIntObject

PyIntObject是一个不可变(immutable)对象。Python内部也大量的使用整数对象,我们在自己的代码中也会有大量的创建销毁整型对象的操作,因此单独的维护整形对象并对其申请内存和释放内存是不现实的。Python给出的解决方案是将整形对象通过一定的结构连接在一起的整数对象系统:整数对象池,一个整形对象的缓冲池机制。

对象创建:

  • PyInt_FromString
  • PyInt_FromLong
  • PyInt_FromUnicode

其中,后两种方法实际上是先转换成浮点数,然后再调用PyInt_FromFloat,这实际上是 Adaptor Pattern 的思想:对核心函数进行接口转换。

2、小整数对象

小整数会频繁的使用。在 Python 中,所有的对象都是存活在系统堆上。这样的操作不仅大大降低了运行效率,而且会在系统堆上造成内存碎片。

所以解决方法就是对小整数使用对象池技术,正是因为使用缓冲池,PyIntObject才是不可变对象。对象池中的每一个对象可以被安全的共享。那么,多小才算小整数?默认的范围是-5到256,这个值不可以动态修改,要想修改只能修改源代码然后重新编译。

3、大整数对象

对于大整数对象,是一次申请一块内存,这块内存用PyIntBlock结构体管理,该结构体中中有一个PyIntObject数组(会链表形式维护)来供大整数对象使用,还有一个用于形成链表的指向下一个block的指针。如果这一整块内存都祸祸光了(默认一个block可以存放82个int对象),就再申请一个PyIntBlock,然后用一个单向链表维护所有的PyIntBlock,这个链表就是大整数对象缓冲池两个重要变量其中之一:block_list指针。

这个 block 链表维护的是一整块block,是block级别的,我要使用的是PyIntObject,每次使用的话总不能进到block去遍历数组去找到一个还没使用的PyIntObject吧,所以下一个大整数缓冲池至关重要的变量就是free_list指针,这个指向一个链表,链表中的所有元素是PyIntObject。

4、引用计数:ob_refcnt

Python通过管理对象的引用计数来决定对象在内存中的存在与否,Python一切皆对象,所有对象都有一个 ob_refcnt 变量。这个变量维护这对象的引用计数,也决定这对象的存在与消亡。

对于某一对象A,当有一个新的PyObject * 引用该对象时,A的引用计数应该增加,而当PyObject * 被删除时, 引用计数应该减少。计数为0时,A 可以从堆上被删除,释放内存。

5、运行时整数对象及其类型之间的关系

对于int(10) 的 ob_refcnt 来说可以理解为多个ref 引用了这个对象,ob_type 是指向其类型对象的指针,ob_ival 是具体数值。

int(10) 是PyIntObject 的实例对象,比PyObject 多一个ob_ival 成员,PyInt_Type、PyBaseObject_Type、PyType_Type 都是PyTypeObject 的实例对象。PyInt_Type 的 tp_base 指向其基类对象 PyBaseObject_Type,而他们的 ob_type 都指向 PyType_Type。

6、不同PyintBlock中空闲内存的互连:tp_dealloc

Python中不同对象在销毁时会进行不同的动作,销毁动作在与对象对应的类对象中被定义,这个关键操作就是类型对象中的tp_dealloc。

static void int_dealloc(PyIntObject *v)
(
    if (PyInt_CheckExact(v))  {
        v->ob_type = (struct _typeobject *)free_list;
        free_list = v;
    }
    else
        v->obtype->tp_free((Pyobject *)v);

tp_dealloc的作用:

由block_list维护的PyIntBlock链表中的内存实际是所有的大整数对象共同分享的。当一个PyIntObject对象被销毁时,它所占的内存并不会被释放,归还给系统,Python会继续保留着。将来提供给别的PyIntObject使用,所以Python应该将其链入了free_list所维护的自由内存链表。

以下是创建可删除PyIntObject对象2、3、4的过程中,内存中对象PyIntObject以及free_list指针的变化:

不同PyIntBlock对象中空闲内存的互连是在int_dealloc被调用时实现的。

 注意:在int_dealloc中,永远不会向系统堆交还任何内存,一旦系统堆中的某块内存被python申请用于整数对象,那么这块内存在Python进程结束之前,将永远不会得到释放。

由于内存共享,Python用于实现该对象池的内存与历史上创建的整数对象的个数无关,而仅仅与同一时刻共存的整数对象个数的最大值有关

————————————————

参考:

  • Python源码剖析(陈孺)

相关文章:

  • 在js中table表格中进行渲染轮播图
  • 优选算法——双指针2
  • 企业OA办公系统开发笔记:2、MyBatis-Plus
  • 定时任务@Scheduled用法及其参数讲解
  • 【论文复刻】堆叠柱状图+饼图
  • 基于Springboot的大学生平时成绩量化管理系统(有报告)。Javaee项目,springboot项目。
  • 代码库管理工具Git介绍
  • InnoDB高级特性篇(5)-使用InnoDB的全文索引
  • 代码随想录刷题训练营day25:LeetCode(216)组合总和III、LeetCode(17)电话号码的字母组合
  • 如何做代币分析:以 TRX 币为例
  • flask流式输出-SSE服务
  • IDEA开发环境热部署
  • 【论文笔记】Radatron: Accurate Detection Using Multi-Resolution Cascaded MIMO Radar
  • 网课题库接口调用方法
  • [附源码]计算机毕业设计大学生心理健康测评系统
  • Blackmagic黑魔法摄像机braw视频文件修复方法
  • 【怎么理解回流与重绘?以及触发场景】
  • Java项目:SSM共享汽车租赁平台
  • Spring框架(十一):手动实现一个@Component,讲一讲Spring的工厂后处理器
  • 集合java
  • MAML:User Diverse Preference Modeling by Multimodal AttentiveMetric Learning
  • 基于MATLAB的一级倒立摆控制仿真,带GUI界面操作显示倒立摆动画,控制器控制输出
  • qt人员管理模块(模块化程序)功能块复制直接使用不冲突
  • 【算法】排序——希尔排序
  • 年产2万吨山楂酒工厂的设计-包装工段及车间的设计(lunwen+任务书+cad图纸)
  • Prophet在R语言中进行时间序列数据预测
  • JavaWeb_第4章_RequestResponse
  • 10 Minimax估计和Bayes估计
  • [NOIP2006 提高组] 作业调度方案
  • 宏鑫科技在创业板过会:前三季度收入约7亿元,王文志为实控人
  • Spring实战之bean重复、指定bean的名字、消除bean的歧义性
  • java通过lock实现同步锁