python 的内存管理架构(objects/obmalloc.c):
复制代码 代码如下:
    _____   ______   ______       ________
   [ int ] [ dict ] [ list ] ... [ string ]       python core         |
+3 |  |  |
    _______________________________       |                           |
   [   python's object allocator   ]      |                           |
+2 | ####### object memory ####### |  |
    ______________________________________________________________    |
   [          python's raw memory allocator (pymem_ api)          ]   |
+1 |  |   |
    __________________________________________________________________
   [    underlying general-purpose allocator (ex: c library malloc)   ]
 0 |  |
     0. c语言库函数提供的接口
    1. pymem_*家族,是对 c中的 malloc、realloc和free 简单的封装,提供底层的控制接口。
    2. pyobject_* 家族,高级的内存控制接口。
    3. 对象类型相关的管理接口
pymem_*
pymem_家族:低级的内存分配接口(low-level memory allocation interfaces)
python 对c中的 malloc、realloc和free 提供了简单的封装:
为什么要这么多次一举:
    不同的c实现对于malloc(0)产生的结果有会所不同,而pymem_malloc(0)会转成malloc(1).      不用的c实现的malloc与free混用会有潜在的问题。python提供封装可以避免这个问题。          python提供了宏和函数,但是宏无法避免这个问题,故编写扩展是应避免使用宏源码:
  include/pymem.h#define pymem_malloc(n) ((size_t)(n) > (size_t)py_ssize_t_max ? null \             : malloc((n) ? (n) : 1))#define pymem_realloc(p, n) ((size_t)(n) > (size_t)py_ssize_t_max ? null \              : realloc((p), (n) ? (n) : 1))#define pymem_free free  objects/object.c/* python's malloc wrappers (see pymem.h) */void *pymem_malloc(size_t nbytes){  return pymem_malloc(nbytes);}...
除了对c的简单封装外,python还提供了4个宏
    pymem_new 和 pymem_new
    pymem_resize和 pymem_resize
它们可以感知类型的大小
#define pymem_new(type, n) \ ( ((size_t)(n) > py_ssize_t_max / sizeof(type)) ? null :   \    ( (type *) pymem_malloc((n) * sizeof(type)) ) )#define pymem_resize(p, type, n) \ ( (p) = ((size_t)(n) > py_ssize_t_max / sizeof(type)) ? null :    \    (type *) pymem_realloc((p), (n) * sizeof(type)) )#define pymem_del        pymem_free#define pymem_del        pymem_free
以下涉及的一些函数仍旧是函数和宏同时存在,下划线后全是大写字符的是宏,后面不再特别说明。
pyobject_*
pyobject_*家族,是高级的内存控制接口(high-level object memory interfaces)。
    注意
      不要和pymem_*家族混用!!      除非有特殊的内粗管理要求,否则应该坚持使用pyobject_*源码
  include/objimpl.h#define pyobject_new(type, typeobj) \        ( (type *) _pyobject_new(typeobj) )#define pyobject_newvar(type, typeobj, n) \        ( (type *) _pyobject_newvar((typeobj), (n)) )  objects/object.cpyobject *_pyobject_new(pytypeobject *tp){  pyobject *op;  op = (pyobject *) pyobject_malloc(_pyobject_size(tp));  if (op == null)    return pyerr_nomemory();  return pyobject_init(op, tp);}pyvarobject *_pyobject_newvar(pytypeobject *tp, py_ssize_t nitems){  pyvarobject *op;  const size_t size = _pyobject_var_size(tp, nitems);  op = (pyvarobject *) pyobject_malloc(size);  if (op == null)    return (pyvarobject *)pyerr_nomemory();  return pyobject_init_var(op, tp, nitems);}
它们执行两项操作:
      分配内存:pyobject_malloc      部分初始化对象:pyobject_init和pyobject_init_var初始化没什么好看到,但是这个malloc就有点复杂无比了...
pyobject_{malloc、free}
这个和pymem_*中的3个可是大不一样了,复杂的厉害!
void * pyobject_malloc(size_t nbytes)void * pyobject_realloc(void *p, size_t nbytes)void pyobject_free(void *p)
python程序运行时频繁地需要创建和销毁小对象,为了避免大量的malloc和free操作,python使用了内存池的技术。
      一系列的 arena(每个管理256kb) 构成一个内存区域的链表      每个 arena 有很多个 pool(每个4kb) 构成      每次内存的申请释放将在一个 pool 内进行单次申请内存块
当申请大小在 1~256 字节之间的内存时,使用内存池(申请0或257字节以上时,将退而使用我们前面提到的pymem_malloc)。
每次申请时,实际分配的空间将按照某个字节数对齐,下表中为8字节(比如pyobject_malloc(20)字节将分配24字节)。
复制代码 代码如下:
request in bytes     size of allocated block      size class idx
  ----------------------------------------------------------------
         1-8                     8                       0
         9-16                   16                       1
        17-24                   24                       2
        25-32                   32                       3
        33-40                   40                       4
         ...                   ...                     ...
       241-248                 248                      30
       249-256                 256                      31
0, 257 and up: routed to the underlying allocator.
这些参数由一些宏进行控制:
#define alignment        8        /* must be 2^n *//* return the number of bytes in size class i, as a uint. */#define index2size(i) (((uint)(i) + 1) << alignment_shift)#define small_request_threshold 256
pool
每次申请的内存块都是需要在 pool 中进行分配,一个pool的大小是 4k。由下列宏进行控制:
#define system_page_size        (4 * 1024)
#define pool_size               system_page_size        /* must be 2^n */
每个pool的头部的定义如下:
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   */};
注意,其中有个成员 szidx,对应前面列表中最后一列的 size class idx。这也说明一个问题:每个 pool 只能分配固定大小的内存块(比如,只分配16字节的块,或者只分配24字节的块...)。
要能分配前面列表中各种大小的内存块,必须有多个 pool。同一大小的pool分配完毕,也需要新的pool。多个pool依次构成一个链表
arena
多个pool对象使用被称为 arena 的东西进行管理。
struct arena_object {  uptr address;  block* pool_address;  uint nfreepools;  uint ntotalpools;  struct pool_header* freepools;  struct arena_object* nextarena;  struct arena_object* prevarena;};
arean控制的内存的大小由下列宏控制:
#define arena_size       (256 << 10)   /* 256kb */
一系列的 arena 构成一个链表。
引用计数与垃圾收集
python中多数对象的生命周期是通过引用计数来控制的,从而实现了内存的动态管理。
但是引用计数有一个致命的问题:循环引用!
为了打破循环引用,python引入了垃圾收集技术。
   
 
   