Python 的內存管理架構(Objects/obmalloc.c):
0. C語言庫函數提供的接口
1. PyMem_*家族,是對 C中的 malloc、realloc和free 簡單的封裝,提供底層的控制接口。
2. PyObject_* 家族,高級的內存控制接口。
3. 對象類型相關的管理接口
PyMem_*
PyMem_家族:低級的內存分配接口(low-level memory allocation interfaces)
Python 對C中的 malloc、realloc和free 提供了簡單的封裝:

為什么要這么多次一舉:
源碼:
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);}...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_*家族,是高級的內存控制接口(high-level object memory interfaces)。
注意
源碼
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);}它們執行兩項操作:
初始化沒什么好看到,但是這個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使用了內存池的技術。
單次申請內存塊
當申請大小在 1~256 字節之間的內存時,使用內存池(申請0或257字節以上時,將退而使用我們前面提到的PyMem_Malloc)。
每次申請時,實際分配的空間將按照某個字節數對齊,下表中為8字節(比如PyObject_Malloc(20)字節將分配24字節)。
這些參數由一些宏進行控制:
#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引入了垃圾收集技術。
新聞熱點
疑難解答
圖片精選