https://blog.csdn.net/zhsenl/article/details/37565519
本文为senlie原创。转载请保留此地址:http://blog.csdn.net/zhengsenlie
1.内存管理架构
Python的内存管理机制都有两套实现:debug模式和release模式
Python内存管理机制的层次结构:
第0层是操作系统提供的内存管理接口,如malloc、free
第1层是Python基于第0层操作系统的内存管理接口包装而成的。主要是为了处理与平台相关的内存分配行为。
实现是一组以PyMem_为前缀的函数族
两套接口:函数和宏。
宏,能够避免函数调用的开销。提高效率,但可能与新版本号的python产生二进制不兼容,假设用C来编写Python的
扩展模块,使用函数接口是一个良好的编程习惯
第2层 以PyObje_为前缀的函数族。主要提供创建Python对象的接口。包含了gc内存管理机制
第3层 对象缓冲池机制
2.小块空间的内存池
Pymalloc机制:内存池机制。管理对小块内存的申请和释放,通过PyObject_Malloc、PyObject_Realloc、PyObject_Free
三个接口显示给Python
整个小块内存的内存池能够视为一个层次结构。分为4层,从下至上各自是:block,pool,arena和内存池
Block
全部block的长度都是8字节对齐的(ALIGNMENT)
SMALL_REQUEST_THRESHOLD:当申请的内存小于这个值时,Python能够使用不同种类的block来满足对内存
的需求。当申请的内存大小超过这个上限。转交请求给第一层内存管理机制。
依据 SMALL_REQUEST_THRESHOLD和 ALIGNMENT的限定,能够得到下面结论:
图
//从size class index转换到size class
#define INDEX2SIZE(I) (((uint)(I) + 1) << ALIGNMENT_SHIFT)
//从size class到size class index
size = (uint )(nbytes - 1) >> ALIGNMENT_SHIFT;
typedef uchar block;
struct pool_header{
union{ block *_padding;
uint count;} ref; //count表示已经分配的block数目
block *freeblock; //指向下一个可用 block
struct pool_header *nextpool; //链接下一个pool
struct pool_header *prevpool; //链接上一个pool
uint arenaindex;
uint szidx; //block 大小的index
uint nextoffset; //指向 freeblock之后的下一个可用的block
uint maxnextoffset; //指向了pool中最后一个可用的block距pool開始位置的偏移
};
#define ROUNDUP(x) (((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK)
#define POOL_OVERHEAD ROUNDUP(sizeof(struct pool_header))
#define struct pool_header *poolp
#define uchar block
poolp pool;
block *bp;
//pool指向了一块4KB的内存
pool->ref.count = 1;
//设置pool的size class index
pool->szidx = size;
//将size class index转换为size,比方3转换为32字节
size = INDEX2SIZE(size);
//跳过用于pool_header的内存,并进行对齐
bp = (block *)pool + POOL_OVERHEAD;
//实际就是pool->nextoffset = POOL_OVERHEAD+size + size
pool->nextoffset = POOL_OVERHEAD + (size << 1);
pool->maxnextoffset = POOL_size - size;
pool->freeblock = bp + size;
if(pool != pool->nextpool){ ++pool->ref.count;
bp = pool->freeblock;
//...
if(pool->nextoffset <= pool->maxnextoffset){
//有足够的空间
pool->freeblock = (block *) pool + pool->nextoffset;
pool->nextoffset += INDEX2SIZE(size);
*(block **)(pool->freeblock) = NULL; //建立离散自由block链表的关键所在
return (void *)bp;
}
}
#define POOL_ADDR(P) ((poolp)((uptr)(p) & ~(uptr)POOL_SIZE_MASK))
void PyObject_Free(void *p){
poolp pool;
block *lastfree;
poolp next, prev;
uint size;
pool = POOL_ADDR(p);
//推断p指向的block是否属于pool
if(Py_ADDRESS_IN_RANGE(p, pool)){
*(block **)p = lastfree = pool->freeblock;//[1]
pool->freeblock = (block *)p;
//...
}
}
typedef uchar block;
struct arena_object{
uptr address;
block *pool_address;
uint nfreepools;
uint ntotalpools;
struct pool_header *freepools;
struct arena_object *nextarena;
struct arena_object *prevarena;
}
//arenas管理着arena_object的集合
static struct arena_object *arenas = NULL;
//当前arenas中管理的 arena_object的个数
static uint maxarenas = 0;
//"未使用"的 arena_object链表
static struct arena_object *unused_arena_objects = NULL;
//”可用“ 的 arena_object链表
static struct arena_object *usable_arenas = NULL;
//初始化时需主持 arena_object的个数
#define INITIAL_ARENA_OBJECTS 16
static struct arena_object *new_arena(void){
struct arena_object *arenaobj;
uint excess;
//[1]:推断是否须要扩充”未使用“的 arena_object列表
if(unused_arena_objects == NULL){
uint i;
uint numarenas;
size_t nbytes;
//[2]:确定本次须要申请的 arena_object的个数,并申请内存
numarenas = maxarenas ? maxarenas << 1 : INITIAL_ARENA_OBJECTS;
if(numarenas <= maxarenas)
return NULL; //溢出
nbytes = numarenas * sizeof(*arenas);
if(nbytes / sizeof(*arenas) != numarenas)
return NULL; //溢出
arenaobj = (struct arena_object *)realloc(arenas, nbytes);
if(arenaobj == NULL)
return NULL;
arenas = arenaobj;
//[3]:初始化新申请的 arena_object。并将其放入 unused_arena_objects链表中
for(i = maxarrenas; i < numarenas; ++i){
arenas[i].address = 0; //mark as unassociated
arenas[i].nextarena = i < numarenas - 1 ? &arenas[i + 1] : NULL;
}
//update globals
unused_arena_objects = &arenas[maxarenas];
maxarenas = numarenas;
}
//[4]:从 unused_arena_objects 链表中取出一个“未使用”的arena_object
arenaobj = unused_arena_objects;
unused_arena_objects = arenaobj->nextarena;
assert(arenaobj->address == 0);
//[5]:申请arena_object管理的内存
arenaobj->address = (uptr)malloc(ARENA_SIZE);
++narenas_currently_allocated;
//[6]:设置pool集合的相关信息
arenaobj->freepools = NULL;
arenaobj->pool_address = (block *)arenaobj->address;
arenaobj->nfreepools = ARENA_SIZE / POOL_SIZE;
//将pool的起始地址调整为系统页的边界
excess = (uint)(arenaobj->address & POOL_SIZE_MASK);
if(excess != 0){
--arenaobj->nfreepools;
arenaobj->pool_address += POOL_SIZE - excess;
}
arenaobj->ntotalpools = arenaobj->nfreepools;
return arenaobj;
}
当申请的内存小于256字节时。PyObject_Malloc会在内存池中申请内存;当申请的内存大于256字节时。
PyObject_Malloc的行为将蜕化为malloc的行为。
当Python申请内存时,最主要的操作单元是pool。由于pool的pool_head里有个szidx,表示block的大小。
一个pool在python执行的不论什么一个时刻,总处于下面三种状态的一种:
used状态、full状态、empty状态
处于used状态的pool被置于usedpools的控制之下。
//todo
3.循环引用的垃圾收集
Python 使用引用计数进行垃圾回收
长处:实时性。不论什么内存,一旦没有指向它的引用,就会马上被回收。为了与引用计数机制搭配。在内存的分配与释放上获得最高的效率,
Python设计了大量内存池机制。
缺点:循环引用。使得一组对象的引用计数都不为0。
-->解决方法:标记-清除,分代收集
三色标记模型
1.寻找root object(全局引用或函数栈中的引用)的集合
2.垃圾检測:从root object 集合出发,沿着root object 集合中的每个引用,假设能到达某个对象A,则A称为可达的
3.垃圾回收:保留可达对象,删除不可达对象
4.Python中的垃圾收集
Python的主要内存管理手段是引用计数机制,为打破循环引用引入了“标记-清除”和“分代收集”
仅仅有container才可能产生循环引用,将创建的container记录在双向链表中
普通Python对象:PyObject_HEAD + 自身数据
?container对象:PyGc_Head + PyObject_HEAD + 自身数据
一个container对象想要成为一个可心仪的对象,必须增加PyGc_Head信息
typedef union _gc_head{
struct{
union _gc_head *gc_next;
union _gc_head *gc_prev;
int gc_refs;
} gc;
long double dummy;
} PyGc_Head;
PyObject *PyDict_New(void){
register dictobject *mp;
//...
mp = PyObject_GC_New(dictobject, &PyDict_Type);
//...
_PyObject_GC_TRACK(mp);//将创建的container对象链接到了Python中的可收集对象链表中。
return (PyObject *)mp;
}
#define _PyObject_GC_TRACK(0) do { PyGc_Head *g = _Py_AS_GC(0); if(g->gc.gc_refs != _PyObject_GC_UNTRACKED) Py_FatalError("GC object already tracked"); g->gc.gc_refs = _PyGC_REFS_REACHABLE; g->gc.gc_next = _PyGC_generations0;
g->gc.gc_prev = _PyGC_generations0->gc.gc_prev; g->gc.gc_prev->gc.gc_prev = g;
_PyGC_generations0->gc.gc_prev = g; } while(0);
#define _PyObject_GC_UNTRACK(0) do{
//...
}
struct gc_generation{
PyGc_Head head;
int threshold; //最多可容纳的container对象,超出这个值会立马触发垃圾回收机制
int count; //已经链接的container对象数目
}
Python中採用三代。一个代用一个链表维护。
原文:https://www.cnblogs.com/mqxnongmin/p/10961929.html