在引用计数降为零后,CPython 如何检测到哪里可以找到 pool_header?
How CPython detects where to find pool_header after reference count goes down to zero?
最近看了一篇关于CPython内存模型的文章:https://rushter.com/blog/python-memory-managment/。文章展示了 CPython 用于管理单个池的以下结构:
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; /* largest valid nextoffset */
};
我不明白的是,如果某个块空闲了,CPython 如何获取这个 header 来更新?我是对的吗,它依赖于一些低级技巧,如果你分配一个 4Kb 大小的页面,那么它的指针会以某种方式对齐,你可以通过将几个位清零来检测页面的开始(可能是 12,因为 2^12=4096 ) 块地址?我说得对吗?
它只是 rounds the block address down 到最近的池对齐值:
/* Round pointer P down to the closest pool-aligned address <= P, as a poolp */
#define POOL_ADDR(P) ((poolp)_Py_ALIGN_DOWN((P), POOL_SIZE))
虽然舍入基本上与您假设的一样,但它之所以有效并不是因为您假设的低级技巧,而是因为 CPython 手动确保池具有必要的对齐方式。当 CPython 分配用于竞技场池的大块内存时,它 sets 竞技场的 pool_address
到该大内存块中的第一个池对齐地址:
/* pool_address <- first pool-aligned address in the arena
nfreepools <- number of whole pools that fit after alignment */
arenaobj->pool_address = (block*)arenaobj->address;
arenaobj->nfreepools = MAX_POOLS_IN_ARENA;
excess = (uint)(arenaobj->address & POOL_SIZE_MASK);
if (excess != 0) {
--arenaobj->nfreepools;
arenaobj->pool_address += POOL_SIZE - excess;
}
最近看了一篇关于CPython内存模型的文章:https://rushter.com/blog/python-memory-managment/。文章展示了 CPython 用于管理单个池的以下结构:
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; /* largest valid nextoffset */
};
我不明白的是,如果某个块空闲了,CPython 如何获取这个 header 来更新?我是对的吗,它依赖于一些低级技巧,如果你分配一个 4Kb 大小的页面,那么它的指针会以某种方式对齐,你可以通过将几个位清零来检测页面的开始(可能是 12,因为 2^12=4096 ) 块地址?我说得对吗?
它只是 rounds the block address down 到最近的池对齐值:
/* Round pointer P down to the closest pool-aligned address <= P, as a poolp */
#define POOL_ADDR(P) ((poolp)_Py_ALIGN_DOWN((P), POOL_SIZE))
虽然舍入基本上与您假设的一样,但它之所以有效并不是因为您假设的低级技巧,而是因为 CPython 手动确保池具有必要的对齐方式。当 CPython 分配用于竞技场池的大块内存时,它 sets 竞技场的 pool_address
到该大内存块中的第一个池对齐地址:
/* pool_address <- first pool-aligned address in the arena
nfreepools <- number of whole pools that fit after alignment */
arenaobj->pool_address = (block*)arenaobj->address;
arenaobj->nfreepools = MAX_POOLS_IN_ARENA;
excess = (uint)(arenaobj->address & POOL_SIZE_MASK);
if (excess != 0) {
--arenaobj->nfreepools;
arenaobj->pool_address += POOL_SIZE - excess;
}