前言
我们前一篇,已经讨论了内存块,这是CPython内存管理模型里面一个基本的逻辑单位,当然block有明确的基本单位那就是8个字节,而对于不同Python对象来说,有着不同类型尺寸(size class)来描述小型Python对象的内存分配需求,内size class index维系内存池和当前块用于什么size class的小型Python对象内存分配的关系。
备注:还有一个重要的分水岭,由于CPython3.6是基于8字节的内存对齐,CPython3.7之后的版本是基于16字节对齐,那么我们勾勒出内存池的逻辑示意图就要分情况讨论啦。
下面我们深入讨论内存池,在此之前请回顾一下这个CPython内存架构图.
Layer 1与Layer 2的内存APIs的交互
池(Pools)
池封装大小相同的块,每个池的大小为4KB,可以查看源代码
/** The system's VMM page size can be obtained on most unices with a* getpagesize() call or deduced from various header files. To make* things simpler, we assume that it is 4K, which is OK for most systems.* It is probably better if this is the native page size, but it doesn't* have to be. In theory, if SYSTEM_PAGE_SIZE is larger than the native page* size, then `POOL_ADDR(p)->arenaindex' could rarely cause a segmentation* violation fault. 4K is apparently OK for all the platforms that python* currently targets.*/
/*源文件Objects/obmalloc.c的第885行*/
#define SYSTEM_PAGE_SIZE (4 * 1024)#define SYSTEM_PAGE_SIZE_MASK (SYSTEM_PAGE_SIZE - 1)....
*
* Size of the pools used for small blocks. Should be a power of 2,
* between 1K and SYSTEM_PAGE_SIZE, that is: 1k, 2k, 4k.
*/
/*源文件Objects/obmalloc.c的第920行*/
#define POOL_SIZE SYSTEM_PAGE_SIZE/* must be 2^N */#define POOL_SIZE_MASK SYSTEM_PAGE_SIZE_MASK
每个池对象由一个叫struct pool_header的结构体来表示,源代码的Objects/obmalloc.c从938到948行的就是池头部定义
/* Pool for small blocks. */
struct pool_header {
union { block *_padding;
uint count; } ref; /* number of allocated blocks */
block *freeblock; /* pool's free list head */
struct pool_header *nextpool; /* next pool of this size class */
struct pool_header *prevpool; /* previous pool "" */
uint arenaindex; /* index into arenas of base adr */
uint szidx; /* block size class index */
uint nextoffset; /* bytes to virgin block */
uint maxnextoffset; /* lar