python 申请内存_Python内存分配器(如何产生一个对象的过程)

本文深入探讨了Python内存分配器的工作原理,包括其分层结构、对象池、arena和pool的概念,以及如何通过内存分配器高效管理内存,特别是在处理小对象时的优化策略。通过了解这些机制,读者可以更好地理解Python内存管理的细节。
摘要由CSDN通过智能技术生成

内存分配器

Python中,当要分配内存时,不单纯使用malloc/free,而是在其基础上堆放三个独立的分层,有效的进行分配。

举个栗子:c语言中申请一片空间就需要使用malloc当释放这个空间的时候就要使用free。Python把这一操作放在最底层也就是0层来实现。那么0层之上是用来做什么呢?我们可能遇到过在python里新建了a=5,b=5两个对象,但是这两个对象id是一样的。这就是Python内存分配器的特点之一,它可以不使用malloc申请空间,而是把对象池里已有的对象返回给你。当这个数字足够大比如说a=560000,b=560000,这时候就会发现两个对象的id是不一样的。这其实就是用了0层的malloc了。

ae8e3126c32bc03d5da8741a8ce5a731.png

Python分配器分层

ee00fe6f358343125cc2a6c2d64279f3.png

第0层往下是OS的功能。-2是隐含和机器的物理性相关联的部分,OS的虚拟内存管理器负责这部分功能。-1层是与机器实际进行交互的部分,OS会执行这部分功能。

第3层到第0层调用了一些具有代表性的函数,下图示:以生成字典对象为例

e8a88f71e462af59677ddb7d6028bc97.png

我们可以看到,生成字典它从第三层的分配器,一直走,层层调用。直到使用malloc申请空间。

第零层--通用的基础分配器

以Linux为例,第0层就是指glibc的malloc()。对系统内存进行申请。

Python中并不是在生成所有对象时都去调用malloc(),而是根据要分配的内存大小来改变分配方法。申请的内存大小如果大于256字节(源码中规定为256,可查看源码),就是用malloc();如果小于256就是用1层或者2层。

Objects/obmalloc.c

#define SMALL_REQUEST_THRESHOLD 256

第一层--低级内存分配器

Python中的对象基本上都是小于等于256字节的,并且几乎都是产生后马上就要被废弃的对象。

在这种情况下,如过逐次从0层分配器开始,就会频繁的malloc和free。效率上会有折扣。

因此再分配小对象时,Python内部就会有特殊的处理。实际上执行这一过程的正是第一层和第二层内存分配器。当需要分配小于等于256字节的对象时,就利用第一层的内存分配器,在这一层会事先从第0层开始迅速保留内存空间,将其蓄积起来。第一层的作用就是管理蓄积的空间。(其实就是一个对象池,上层对它进行管理,以应对频繁产生又释放的对象。)

内存结构

根据管理的空间不同,他们各自的叫法也不同。他们之间的关系式包含关系。

最小的单位为block,最终给申请者的就是block的地址。

比他大的是pool(pool包含block)。

最大的是arena(arena包含pool)。

6f29b234bd311ae1ca1f3d838bad6e15.png

arena > pool >block。为避免频繁的嗲用malloc和free,第0层分配器会以最大的单位arena来保留内存。pool是用于有效管理空的block的。

arena

Objects/objmalloc.c

struct arena_object {

/* malloc后的arena的地址*/

uptr address;

/* 将arena的地址用于给pool使用而对齐的地址 */

block* pool_address;

/* 此arena中空闲的pool数量 */

uint nfreepools;

/* 此arena中pool的总数 */

uint ntotalpools;

/* 连接空闲pool的单向链表 */

struct pool_header* freepools;

/* 稍后说明 */

struct arena_object* nextarena;

struct arena_object* prevarena;

};

以上就是 arena_object结构体,它管理者arena。

arena_object的成员address保存的是使用第0层内存分配器分配的arena地址。arena大小固定为256k。此大小也是宏定义好的。

arena_object的成员pool_address中保存的是arena里开头的pool地址。这里有个问题,为什么除了域address之外还要一个pool地址呢?arena的地址和其中第一个的pool地址应该是一致的呀!这是因为我们用到了系统中的页,为了使用页的功能,所以要和页对齐才导致arena地址不是第一个pool地址。(之后又详细说明)

arena_object还承担着保持被分配的pool的数量,将空pool连接到单向链表的功能。

此外arena_object被数组arenas管理。

Objects/obmalloc.c

/* 将arena_object作为元素的数组 */

static struct arena_object* arenas = NULL;

/* arenas的元素数量 */

static uint maxarenas = 0;

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值