內(nèi)存管理?
概述?
在 Python 中,內(nèi)存管理涉及到一個(gè)包含所有 Python 對(duì)象和數(shù)據(jù)結(jié)構(gòu)的私有堆(heap)。這個(gè)私有堆的管理由內(nèi)部的 Python 內(nèi)存管理器(Python memory manager) 保證。Python 內(nèi)存管理器有不同的組件來(lái)處理各種動(dòng)態(tài)存儲(chǔ)管理方面的問題,如共享、分割、預(yù)分配或緩存。
在最底層,一個(gè)原始內(nèi)存分配器通過與操作系統(tǒng)的內(nèi)存管理器交互,確保私有堆中有足夠的空間來(lái)存儲(chǔ)所有與 Python 相關(guān)的數(shù)據(jù)。在原始內(nèi)存分配器的基礎(chǔ)上,幾個(gè)對(duì)象特定的分配器在同一堆上運(yùn)行,并根據(jù)每種對(duì)象類型的特點(diǎn)實(shí)現(xiàn)不同的內(nèi)存管理策略。例如,整數(shù)對(duì)象在堆內(nèi)的管理方式不同于字符串、元組或字典,因?yàn)檎麛?shù)需要不同的存儲(chǔ)需求和速度與空間的權(quán)衡。因此,Python 內(nèi)存管理器將一些工作分配給對(duì)象特定分配器,但確保后者在私有堆的范圍內(nèi)運(yùn)行。
Python 堆內(nèi)存的管理是由解釋器來(lái)執(zhí)行,用戶對(duì)它沒有控制權(quán),即使他們經(jīng)常操作指向堆內(nèi)內(nèi)存塊的對(duì)象指針,理解這一點(diǎn)十分重要。Python 對(duì)象和其他內(nèi)部緩沖區(qū)的堆空間分配是由 Python 內(nèi)存管理器按需通過本文檔中列出的 Python/C API 函數(shù)進(jìn)行的。
為了避免內(nèi)存破壞,擴(kuò)展的作者永遠(yuǎn)不應(yīng)該試圖用 C 庫(kù)函數(shù)導(dǎo)出的函數(shù)來(lái)對(duì) Python 對(duì)象進(jìn)行操作,這些函數(shù)包括: malloc()
, calloc()
, realloc()
和 free()
。這將導(dǎo)致 C 分配器和 Python 內(nèi)存管理器之間的混用,引發(fā)嚴(yán)重后果,這是由于它們實(shí)現(xiàn)了不同的算法,并在不同的堆上操作。但是,我們可以安全地使用 C 庫(kù)分配器為單獨(dú)的目的分配和釋放內(nèi)存塊,如下例所示:
PyObject *res;
char *buf = (char *) malloc(BUFSIZ); /* for I/O */
if (buf == NULL)
return PyErr_NoMemory();
...Do some I/O operation involving buf...
res = PyBytes_FromString(buf);
free(buf); /* malloc'ed */
return res;
在這個(gè)例子中,I/O 緩沖區(qū)的內(nèi)存請(qǐng)求是由 C 庫(kù)分配器處理的。Python 內(nèi)存管理器只參與了分配作為結(jié)果返回的字節(jié)對(duì)象。
然而,在大多數(shù)情況下,建議專門從 Python 堆中分配內(nèi)存,因?yàn)楹笳哂?Python 內(nèi)存管理器控制。例如,當(dāng)解釋器擴(kuò)展了用 C 寫的新對(duì)象類型時(shí),就必須這樣做。使用 Python 堆的另一個(gè)原因是希望*通知* Python 內(nèi)存管理器關(guān)于擴(kuò)展模塊的內(nèi)存需求。即使所請(qǐng)求的內(nèi)存全部只用于內(nèi)部的、高度特定的目的,將所有的內(nèi)存請(qǐng)求交給 Python 內(nèi)存管理器能讓解釋器對(duì)其內(nèi)存占用的整體情況有更準(zhǔn)確的了解。因此,在某些情況下,Python 內(nèi)存管理器可能會(huì)觸發(fā)或不觸發(fā)適當(dāng)?shù)牟僮鳎缋厥?、?nèi)存壓縮或其他預(yù)防性操作。請(qǐng)注意,通過使用前面例子中所示的 C 庫(kù)分配器,為 I/O 緩沖區(qū)分配的內(nèi)存會(huì)完全不受 Python 內(nèi)存管理器管理。
參見
環(huán)境變量 PYTHONMALLOC
可被用來(lái)配置 Python 所使用的內(nèi)存分配器。
環(huán)境變量 PYTHONMALLOCSTATS
可以用來(lái)在每次創(chuàng)建和關(guān)閉新的 pymalloc 對(duì)象區(qū)域時(shí)打印 pymalloc 內(nèi)存分配器 的統(tǒng)計(jì)數(shù)據(jù)。
Allocator Domains?
All allocating functions belong to one of three different "domains" (see also
PyMemAllocatorDomain
). These domains represent different allocation
strategies and are optimized for different purposes. The specific details on
how every domain allocates memory or what internal functions each domain calls
is considered an implementation detail, but for debugging purposes a simplified
table can be found at here. There is no hard
requirement to use the memory returned by the allocation functions belonging to
a given domain for only the purposes hinted by that domain (although this is the
recommended practice). For example, one could use the memory returned by
PyMem_RawMalloc()
for allocating Python objects or the memory returned
by PyObject_Malloc()
for allocating memory for buffers.
The three allocation domains are:
Raw domain: intended for allocating memory for general-purpose memory buffers where the allocation must go to the system allocator or where the allocator can operate without the GIL. The memory is requested directly to the system.
"Mem" domain: intended for allocating memory for Python buffers and general-purpose memory buffers where the allocation must be performed with the GIL held. The memory is taken from the Python private heap.
Object domain: intended for allocating memory belonging to Python objects. The memory is taken from the Python private heap.
When freeing memory previously allocated by the allocating functions belonging to a
given domain,the matching specific deallocating functions must be used. For example,
PyMem_Free()
must be used to free memory allocated using PyMem_Malloc()
.
原始內(nèi)存接口?
以下函數(shù)集封裝了系統(tǒng)分配器。這些函數(shù)是線程安全的,不需要持有 全局解釋器鎖。
default raw memory allocator 使用這些函數(shù):malloc()
、 calloc()
、 realloc()
和 free()
;申請(qǐng)零字節(jié)時(shí)則調(diào)用 malloc(1)
(或 calloc(1, 1)
)
3.4 新版功能.
-
void *PyMem_RawMalloc(size_t n)?
分配 n 個(gè)字節(jié)并返回一個(gè)指向分配的內(nèi)存的 void* 類型指針,如果請(qǐng)求失敗則返回
NULL
。請(qǐng)求零字節(jié)可能返回一個(gè)獨(dú)特的非
NULL
指針,就像調(diào)用了PyMem_RawMalloc(1)
一樣。但是內(nèi)存不會(huì)以任何方式被初始化。
-
void *PyMem_RawCalloc(size_t nelem, size_t elsize)?
分配 nelem 個(gè)元素,每個(gè)元素的大小為 elsize 字節(jié),并返回指向分配的內(nèi)存的 void* 類型指針,如果請(qǐng)求失敗則返回
NULL
。 內(nèi)存會(huì)被初始化為零。請(qǐng)求零字節(jié)可能返回一個(gè)獨(dú)特的非
NULL
指針,就像調(diào)用了PyMem_RawCalloc(1, 1)
一樣。3.5 新版功能.
-
void *PyMem_RawRealloc(void *p, size_t n)?
將 p 指向的內(nèi)存塊大小調(diào)整為 n 字節(jié)。以新舊內(nèi)存塊大小中的最小值為準(zhǔn),其中內(nèi)容保持不變,
如果 p 是
NULL
,則相當(dāng)于調(diào)用PyMem_RawMalloc(n)
;如果 n 等于 0,則內(nèi)存塊大小會(huì)被調(diào)整,但不會(huì)被釋放,返回非NULL
指針。除非 p 是
NULL
,否則它必須是之前調(diào)用PyMem_RawMalloc()
、PyMem_RawRealloc()
或PyMem_RawCalloc()
所返回的。如果請(qǐng)求失敗,
PyMem_RawRealloc()
返回NULL
, p 仍然是指向先前內(nèi)存區(qū)域的有效指針。
-
void PyMem_RawFree(void *p)?
釋放 p 指向的內(nèi)存塊。 p 必須是之前調(diào)用
PyMem_RawMalloc()
、PyMem_RawRealloc()
或PyMem_RawCalloc()
所返回的指針。否則,或在PyMem_RawFree(p)
之前已經(jīng)調(diào)用過的情況下,未定義的行為會(huì)發(fā)生。如果 p 是
NULL
, 那么什么操作也不會(huì)進(jìn)行。
內(nèi)存接口?
以下函數(shù)集,仿照 ANSI C 標(biāo)準(zhǔn),并指定了請(qǐng)求零字節(jié)時(shí)的行為,可用于從Python堆分配和釋放內(nèi)存。
默認(rèn)內(nèi)存分配器 使用了 pymalloc 內(nèi)存分配器.
警告
在使用這些函數(shù)時(shí),必須持有 全局解釋器鎖(GIL) 。
在 3.6 版更改: 現(xiàn)在默認(rèn)的分配器是 pymalloc 而非系統(tǒng)的 malloc()
。
-
void *PyMem_Malloc(size_t n)?
- Part of the Stable ABI.
分配 n 個(gè)字節(jié)并返回一個(gè)指向分配的內(nèi)存的 void* 類型指針,如果請(qǐng)求失敗則返回
NULL
。請(qǐng)求零字節(jié)可能返回一個(gè)獨(dú)特的非
NULL
指針,就像調(diào)用了PyMem_Malloc(1)
一樣。但是內(nèi)存不會(huì)以任何方式被初始化。
-
void *PyMem_Calloc(size_t nelem, size_t elsize)?
- Part of the Stable ABI since version 3.7.
分配 nelem 個(gè)元素,每個(gè)元素的大小為 elsize 字節(jié),并返回指向分配的內(nèi)存的 void* 類型指針,如果請(qǐng)求失敗則返回
NULL
。 內(nèi)存會(huì)被初始化為零。請(qǐng)求零字節(jié)可能返回一個(gè)獨(dú)特的非
NULL
指針,就像調(diào)用了PyMem_Calloc(1, 1)
一樣。3.5 新版功能.
-
void *PyMem_Realloc(void *p, size_t n)?
- Part of the Stable ABI.
將 p 指向的內(nèi)存塊大小調(diào)整為 n 字節(jié)。以新舊內(nèi)存塊大小中的最小值為準(zhǔn),其中內(nèi)容保持不變,
如果 p 是
NULL
,則相當(dāng)于調(diào)用PyMem_Malloc(n)
;如果 n 等于 0,則內(nèi)存塊大小會(huì)被調(diào)整,但不會(huì)被釋放,返回非NULL
指針。除非 p 是
NULL
,否則它必須是之前調(diào)用PyMem_Malloc()
、PyMem_Realloc()
或PyMem_Calloc()
所返回的。如果請(qǐng)求失敗,
PyMem_Realloc()
返回NULL
, p 仍然是指向先前內(nèi)存區(qū)域的有效指針。
-
void PyMem_Free(void *p)?
- Part of the Stable ABI.
釋放 p 指向的內(nèi)存塊。 p 必須是之前調(diào)用
PyMem_Malloc()
、PyMem_Realloc()
或PyMem_Calloc()
所返回的指針。否則,或在PyMem_Free(p)
之前已經(jīng)調(diào)用過的情況下,未定義的行為會(huì)發(fā)生。如果 p 是
NULL
, 那么什么操作也不會(huì)進(jìn)行。
以下面向類型的宏為方便而提供。 注意 TYPE 可以指任何 C 類型。
-
TYPE *PyMem_New(TYPE, size_t n)?
與
PyMem_Malloc()
相同,但會(huì)分配(n * sizeof(TYPE))
字節(jié)的內(nèi)存。 返回一個(gè)轉(zhuǎn)換為 TYPE* 的指針。 內(nèi)存將不會(huì)以任何方式被初始化。
-
TYPE *PyMem_Resize(void *p, TYPE, size_t n)?
與
PyMem_Realloc()
相同,但內(nèi)存塊的大小被調(diào)整為(n * sizeof(TYPE))
字節(jié)。 返回一個(gè)轉(zhuǎn)換為 TYPE* 類型的指針。 返回時(shí),p 將為指向新內(nèi)存區(qū)域的指針,如果失敗則返回NULL
。這是一個(gè) C 預(yù)處理宏, p 總是被重新賦值。請(qǐng)保存 p 的原始值,以避免在處理錯(cuò)誤時(shí)丟失內(nèi)存。
-
void PyMem_Del(void *p)?
與
PyMem_Free()
相同
此外,我們還提供了以下宏集用于直接調(diào)用 Python 內(nèi)存分配器,而不涉及上面列出的 C API 函數(shù)。但是請(qǐng)注意,使用它們并不能保證跨 Python 版本的二進(jìn)制兼容性,因此在擴(kuò)展模塊被棄用。
PyMem_MALLOC(size)
PyMem_NEW(type, size)
PyMem_REALLOC(ptr, size)
PyMem_RESIZE(ptr, type, size)
PyMem_FREE(ptr)
PyMem_DEL(ptr)
對(duì)象分配器?
以下函數(shù)集,仿照 ANSI C 標(biāo)準(zhǔn),并指定了請(qǐng)求零字節(jié)時(shí)的行為,可用于從Python堆分配和釋放內(nèi)存。
備注
There is no guarantee that the memory returned by these allocators can be successfully cast to a Python object when intercepting the allocating functions in this domain by the methods described in the Customize Memory Allocators section.
默認(rèn)對(duì)象分配器 使用 pymalloc 內(nèi)存分配器.
警告
在使用這些函數(shù)時(shí),必須持有 全局解釋器鎖(GIL) 。
-
void *PyObject_Malloc(size_t n)?
- Part of the Stable ABI.
分配 n 個(gè)字節(jié)并返回一個(gè)指向分配的內(nèi)存的 void* 類型指針,如果請(qǐng)求失敗則返回
NULL
。請(qǐng)求零字節(jié)可能返回一個(gè)獨(dú)特的非
NULL
指針,就像調(diào)用了PyObject_Malloc(1)
一樣。但是內(nèi)存不會(huì)以任何方式被初始化。
-
void *PyObject_Calloc(size_t nelem, size_t elsize)?
- Part of the Stable ABI since version 3.7.
分配 nelem 個(gè)元素,每個(gè)元素的大小為 elsize 字節(jié),并返回指向分配的內(nèi)存的 void* 類型指針,如果請(qǐng)求失敗則返回
NULL
。 內(nèi)存會(huì)被初始化為零。請(qǐng)求零字節(jié)可能返回一個(gè)獨(dú)特的非
NULL
指針,就像調(diào)用了PyObject_Calloc(1, 1)
一樣。3.5 新版功能.
-
void PyObject_Realloc(void *p, size_t n)?
- Part of the Stable ABI.
將 p 指向的內(nèi)存塊大小調(diào)整為 n 字節(jié)。以新舊內(nèi)存塊大小中的最小值為準(zhǔn),其中內(nèi)容保持不變,
如果*p*是``NULL``,則相當(dāng)于調(diào)用
PyObject_Malloc(n)
;如果 n 等于 0,則內(nèi)存塊大小會(huì)被調(diào)整,但不會(huì)被釋放,返回非NULL
指針。除非 p 是
NULL
,否則它必須是之前調(diào)用PyObject_Malloc()
、PyObject_Realloc()
或PyObject_Calloc()
所返回的。如果請(qǐng)求失敗,
PyObject_Realloc()
返回NULL
, p 仍然是指向先前內(nèi)存區(qū)域的有效指針。
-
void PyObject_Free(void *p)?
- Part of the Stable ABI.
釋放 p 指向的內(nèi)存塊。 p 必須是之前調(diào)用
PyObject_Malloc()
、PyObject_Realloc()
或PyObject_Calloc()
所返回的指針。否則,或在PyObject_Free(p)
之前已經(jīng)調(diào)用過的情況下,未定義行為會(huì)發(fā)生。如果 p 是
NULL
, 那么什么操作也不會(huì)進(jìn)行。
默認(rèn)內(nèi)存分配器?
默認(rèn)內(nèi)存分配器:
配置 |
名稱 |
PyMem_RawMalloc |
PyMem_Malloc |
PyObject_Malloc |
---|---|---|---|---|
發(fā)布版本 |
|
|
|
|
調(diào)試構(gòu)建 |
|
|
|
|
沒有 pymalloc 的發(fā)布版本 |
|
|
|
|
沒有 pymalloc 的調(diào)試構(gòu)建 |
|
|
|
|
說明:
Name: value for
PYTHONMALLOC
environment variable.malloc
: system allocators from the standard C library, C functions:malloc()
,calloc()
,realloc()
andfree()
.pymalloc
: pymalloc memory allocator."+ debug": with debug hooks on the Python memory allocators.
"Debug build": Python build in debug mode.
自定義內(nèi)存分配器?
3.4 新版功能.
-
type PyMemAllocatorEx?
Structure used to describe a memory block allocator. The structure has the following fields:
域
含意
void *ctx
作為第一個(gè)參數(shù)傳入的用戶上下文
void* malloc(void *ctx, size_t size)
分配一個(gè)內(nèi)存塊
void* calloc(void *ctx, size_t nelem, size_t elsize)
分配一個(gè)初始化為 0 的內(nèi)存塊
void* realloc(void *ctx, void *ptr, size_t new_size)
分配一個(gè)內(nèi)存塊或調(diào)整其大小
void free(void *ctx, void *ptr)
釋放一個(gè)內(nèi)存塊
在 3.5 版更改: The
PyMemAllocator
structure was renamed toPyMemAllocatorEx
and a newcalloc
field was added.
-
type PyMemAllocatorDomain?
用來(lái)識(shí)別分配器域的枚舉類。域有:
-
PYMEM_DOMAIN_RAW?
函數(shù)
-
PYMEM_DOMAIN_MEM?
函數(shù)
-
PYMEM_DOMAIN_OBJ?
函數(shù)
-
PYMEM_DOMAIN_RAW?
-
void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)?
獲取指定域的內(nèi)存塊分配器。
-
void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)?
設(shè)置指定域的內(nèi)存塊分配器。
當(dāng)請(qǐng)求零字節(jié)時(shí),新的分配器必須返回一個(gè)獨(dú)特的非
NULL
指針。對(duì)于
PYMEM_DOMAIN_RAW
域,分配器必須是線程安全的:當(dāng)分配器被調(diào)用時(shí),不持有 全局解釋器鎖 。如果新的分配器不是鉤子(不調(diào)用之前的分配器),必須調(diào)用
PyMem_SetupDebugHooks()
函數(shù)在新分配器上重新安裝調(diào)試鉤子。See also
PyPreConfig.allocator
and Preinitialize Python with PyPreConfig.
-
void PyMem_SetupDebugHooks(void)?
Setup debug hooks in the Python memory allocators to detect memory errors.
Debug hooks on the Python memory allocators?
When Python is built in debug mode, the
PyMem_SetupDebugHooks()
function is called at the Python
preinitialization to setup debug hooks on Python memory allocators
to detect memory errors.
The PYTHONMALLOC
environment variable can be used to install debug
hooks on a Python compiled in release mode (ex: PYTHONMALLOC=debug
).
The PyMem_SetupDebugHooks()
function can be used to set debug hooks
after calling PyMem_SetAllocator()
.
These debug hooks fill dynamically allocated memory blocks with special,
recognizable bit patterns. Newly allocated memory is filled with the byte
0xCD
(PYMEM_CLEANBYTE
), freed memory is filled with the byte 0xDD
(PYMEM_DEADBYTE
). Memory blocks are surrounded by "forbidden bytes"
filled with the byte 0xFD
(PYMEM_FORBIDDENBYTE
). Strings of these bytes
are unlikely to be valid addresses, floats, or ASCII strings.
運(yùn)行時(shí)檢查:
Detect API violations. For example, detect if
PyObject_Free()
is called on a memory block allocated byPyMem_Malloc()
.Detect write before the start of the buffer (buffer underflow).
Detect write after the end of the buffer (buffer overflow).
Check that the GIL is held when allocator functions of
PYMEM_DOMAIN_OBJ
(ex:PyObject_Malloc()
) andPYMEM_DOMAIN_MEM
(ex:PyMem_Malloc()
) domains are called.
在出錯(cuò)時(shí),調(diào)試鉤子使用 tracemalloc
模塊來(lái)回溯內(nèi)存塊被分配的位置。只有當(dāng) tracemalloc
正在追蹤 Python 內(nèi)存分配,并且內(nèi)存塊被追蹤時(shí),才會(huì)顯示回溯。
Let S = sizeof(size_t)
. 2*S
bytes are added at each end of each block
of N bytes requested. The memory layout is like so, where p represents the
address returned by a malloc-like or realloc-like function (p[i:j]
means
the slice of bytes from *(p+i)
inclusive up to *(p+j)
exclusive; note
that the treatment of negative indices differs from a Python slice):
p[-2*S:-S]
Number of bytes originally asked for. This is a size_t, big-endian (easier to read in a memory dump).
p[-S]
API identifier (ASCII character):
'r'
forPYMEM_DOMAIN_RAW
.'m'
forPYMEM_DOMAIN_MEM
.'o'
forPYMEM_DOMAIN_OBJ
.
p[-S+1:0]
Copies of PYMEM_FORBIDDENBYTE. Used to catch under- writes and reads.
p[0:N]
The requested memory, filled with copies of PYMEM_CLEANBYTE, used to catch reference to uninitialized memory. When a realloc-like function is called requesting a larger memory block, the new excess bytes are also filled with PYMEM_CLEANBYTE. When a free-like function is called, these are overwritten with PYMEM_DEADBYTE, to catch reference to freed memory. When a realloc- like function is called requesting a smaller memory block, the excess old bytes are also filled with PYMEM_DEADBYTE.
p[N:N+S]
Copies of PYMEM_FORBIDDENBYTE. Used to catch over- writes and reads.
p[N+S:N+2*S]
Only used if the
PYMEM_DEBUG_SERIALNO
macro is defined (not defined by default).A serial number, incremented by 1 on each call to a malloc-like or realloc-like function. Big-endian
size_t
. If "bad memory" is detected later, the serial number gives an excellent way to set a breakpoint on the next run, to capture the instant at which this block was passed out. The static function bumpserialno() in obmalloc.c is the only place the serial number is incremented, and exists so you can set such a breakpoint easily.
A realloc-like or free-like function first checks that the PYMEM_FORBIDDENBYTE bytes at each end are intact. If they've been altered, diagnostic output is written to stderr, and the program is aborted via Py_FatalError(). The other main failure mode is provoking a memory error when a program reads up one of the special bit patterns and tries to use it as an address. If you get in a debugger then and look at the object, you're likely to see that it's entirely filled with PYMEM_DEADBYTE (meaning freed memory is getting used) or PYMEM_CLEANBYTE (meaning uninitialized memory is getting used).
在 3.6 版更改: The PyMem_SetupDebugHooks()
function now also works on Python
compiled in release mode. On error, the debug hooks now use
tracemalloc
to get the traceback where a memory block was allocated.
The debug hooks now also check if the GIL is held when functions of
PYMEM_DOMAIN_OBJ
and PYMEM_DOMAIN_MEM
domains are
called.
在 3.8 版更改: Byte patterns 0xCB
(PYMEM_CLEANBYTE
), 0xDB
(PYMEM_DEADBYTE
)
and 0xFB
(PYMEM_FORBIDDENBYTE
) have been replaced with 0xCD
,
0xDD
and 0xFD
to use the same values than Windows CRT debug
malloc()
and free()
.
pymalloc 分配器?
Python 有為具有短生命周期的小對(duì)象(小于或等于 512 字節(jié))優(yōu)化的 pymalloc 分配器。它使用固定大小為 256 KiB 的稱為 "arenas" 的內(nèi)存映射。對(duì)于大于512字節(jié)的分配,它回到使用 PyMem_RawMalloc()
和 PyMem_RawRealloc()
。
pymalloc 是 PYMEM_DOMAIN_MEM
(例如: PyMem_Malloc()
) 和 PYMEM_DOMAIN_OBJ
(例如: PyObject_Malloc()
) 域的 默認(rèn)分配器 。
arena 分配器使用以下函數(shù):
Windows 上的
VirtualAlloc()
和VirtualFree()
,mmap()
和munmap()
,如果可用,否則,
malloc()
和free()
。
This allocator is disabled if Python is configured with the
--without-pymalloc
option. It can also be disabled at runtime using
the PYTHONMALLOC
environment variable (ex: PYTHONMALLOC=malloc
).
自定義 pymalloc Arena 分配器?
3.4 新版功能.
-
type PyObjectArenaAllocator?
用來(lái)描述一個(gè) arena 分配器的結(jié)構(gòu)體。這個(gè)結(jié)構(gòu)體有三個(gè)字段:
域
含意
void *ctx
作為第一個(gè)參數(shù)傳入的用戶上下文
void* alloc(void *ctx, size_t size)
分配一塊 size 字節(jié)的區(qū)域
void free(void *ctx, void *ptr, size_t size)
釋放一塊區(qū)域
-
void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)?
獲取 arena 分配器
-
void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)?
設(shè)置 arena 分配器
tracemalloc C API?
3.7 新版功能.
-
int PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, size_t size)?
在
tracemalloc
模塊中跟蹤一個(gè)已分配的內(nèi)存塊。成功時(shí)返回
0
,出錯(cuò)時(shí)返回-1
(無(wú)法分配內(nèi)存來(lái)保存跟蹤信息)。 如果禁用了 tracemalloc 則返回-2
。如果內(nèi)存塊已被跟蹤,則更新現(xiàn)有跟蹤信息。
-
int PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)?
在
tracemalloc
模塊中取消跟蹤一個(gè)已分配的內(nèi)存塊。 如果內(nèi)存塊未被跟蹤則不執(zhí)行任何操作。如果 tracemalloc 被禁用則返回
-2
,否則返回0
。
例子?
以下是來(lái)自 概述 小節(jié)的示例,經(jīng)過重寫以使 I/O 緩沖區(qū)是通過使用第一個(gè)函數(shù)集從 Python 堆中分配的:
PyObject *res;
char *buf = (char *) PyMem_Malloc(BUFSIZ); /* for I/O */
if (buf == NULL)
return PyErr_NoMemory();
/* ...Do some I/O operation involving buf... */
res = PyBytes_FromString(buf);
PyMem_Free(buf); /* allocated with PyMem_Malloc */
return res;
使用面向類型函數(shù)集的相同代碼:
PyObject *res;
char *buf = PyMem_New(char, BUFSIZ); /* for I/O */
if (buf == NULL)
return PyErr_NoMemory();
/* ...Do some I/O operation involving buf... */
res = PyBytes_FromString(buf);
PyMem_Del(buf); /* allocated with PyMem_New */
return res;
請(qǐng)注意在以上兩個(gè)示例中,緩沖區(qū)總是通過歸屬于相同集的函數(shù)來(lái)操縱的。 事實(shí)上,對(duì)于一個(gè)給定的內(nèi)存塊必須使用相同的內(nèi)存 API 族,以便使得混合不同分配器的風(fēng)險(xiǎn)減至最低。 以下代碼序列包含兩處錯(cuò)誤,其中一個(gè)被標(biāo)記為 fatal 因?yàn)樗旌狭藘煞N在不同堆上操作的不同分配器。
char *buf1 = PyMem_New(char, BUFSIZ);
char *buf2 = (char *) malloc(BUFSIZ);
char *buf3 = (char *) PyMem_Malloc(BUFSIZ);
...
PyMem_Del(buf3); /* Wrong -- should be PyMem_Free() */
free(buf2); /* Right -- allocated via malloc() */
free(buf1); /* Fatal -- should be PyMem_Del() */
除了旨在處理來(lái)自 Python 堆的原始內(nèi)存塊的函數(shù)之外, Python 中的對(duì)象是通過 PyObject_New()
, PyObject_NewVar()
和 PyObject_Del()
來(lái)分配和釋放的。
這些將在有關(guān)如何在 C 中定義和實(shí)現(xiàn)新對(duì)象類型的下一章中講解。