python-内存管理
python对大于512字节的对象会使用malloc动态申请内存,对于小于512字节的对象使用内存池。
内存池分三个等级block、pool和arena。
block
block是一个8字节为步长的大小固定的内存块,总共64种block,从小到大依次是8字节,16字节、24字节、32字节直到512字节。
图片来源:古明地觉的公众号
在分配内存时也是以内存块为基准,只包含内部碎片。比如说需要5字节内存,分配一个8字节的内存块,需要10字节分配一个16字节的内存块。
pool
一组block集合称为一个pool,一个pool管理着一堆具有固定大小的内存块,一个pool的大小通常为一个系统内存页,即4kb。
pool内部每一个的block大小相同,pool间可能不同也可能相同。
class Pool:
count: int # 已分配块数
sizeidx: int # block种类id,0表示8字节,1表示16字节,2表示24字节
freeblock: block # 第一个可用块地址
nextoffset: block # 下一个可用块地址,即第二个可用块地址
maxnextoffset: block # 最后一个可用块地址
nextpool:pool
prevpool:pool
arenaidx:int
arena
pool的集合就是arena,arena的大小是256kb,python一开始默认申请16个arena。一个arena有64个pool,pool之间会形成一个链表。而arean之间组成的是一个数组。
class Arean:
pool_address: pool # 下一个被划分的pool,pool只有在被使用的适合才会决定其内部block大小
nfreepools: int # 可用pool数量
ntotalpools: int # arean中所有pool的数量
feepools: pool # 第一个可用pool
nextarean:arean
prevarena:arena
arena是通过数组进行组织起来的,这个数组(areans)就是内存池,arena又分为可用和未使用的arean,未使用的arena通过单向链表组织起来,可用的arena通过双向链表组织。
pool中block的集合是一段连续内存,pool申请时,block也申请了。但是arean中的pool集合并不是连续内存。
python在申请内存时基本的操作单元是pool而不是arena。
管理同类型的pool之间会组成一个双向链表,所以used状态的pool有64条双向链表。这 64 条双向链表会放在一个名为 usedpools 的数组中。
在申请内存时,会优先从最满的arena的最满的pool中找到第一个合适的block返回。
当一个pool所有的block都用完的会从usedpools的相应链表中移除,当有一个block被释放时,pool会被插入到头结点,以保证优先从最满 的pool里寻找block。