新聞中心
內(nèi)存管理
概述
在 python 中,內(nèi)存管理涉及到一個包含所有 Python 對象和數(shù)據(jù)結(jié)構(gòu)的私有堆(heap)。這個私有堆的管理由內(nèi)部的 Python 內(nèi)存管理器(Python memory manager) 保證。Python 內(nèi)存管理器有不同的組件來處理各種動態(tài)存儲管理方面的問題,如共享、分割、預(yù)分配或緩存。

成都創(chuàng)新互聯(lián)為您提適合企業(yè)的網(wǎng)站設(shè)計(jì)?讓您的網(wǎng)站在搜索引擎具有高度排名,讓您的網(wǎng)站具備超強(qiáng)的網(wǎng)絡(luò)競爭力!結(jié)合企業(yè)自身,進(jìn)行網(wǎng)站設(shè)計(jì)及把握,最后結(jié)合企業(yè)文化和具體宗旨等,才能創(chuàng)作出一份性化解決方案。從網(wǎng)站策劃到成都網(wǎng)站建設(shè)、做網(wǎng)站, 我們的網(wǎng)頁設(shè)計(jì)師為您提供的解決方案。
在最底層,一個原始內(nèi)存分配器通過與操作系統(tǒng)的內(nèi)存管理器交互,確保私有堆中有足夠的空間來存儲所有與 Python 相關(guān)的數(shù)據(jù)。在原始內(nèi)存分配器的基礎(chǔ)上,幾個對象特定的分配器在同一堆上運(yùn)行,并根據(jù)每種對象類型的特點(diǎn)實(shí)現(xiàn)不同的內(nèi)存管理策略。例如,整數(shù)對象在堆內(nèi)的管理方式不同于字符串、元組或字典,因?yàn)檎麛?shù)需要不同的存儲需求和速度與空間的權(quán)衡。因此,Python 內(nèi)存管理器將一些工作分配給對象特定分配器,但確保后者在私有堆的范圍內(nèi)運(yùn)行。
Python 堆內(nèi)存的管理是由解釋器來執(zhí)行,用戶對它沒有控制權(quán),即使他們經(jīng)常操作指向堆內(nèi)內(nèi)存塊的對象指針,理解這一點(diǎn)十分重要。Python 對象和其他內(nèi)部緩沖區(qū)的堆空間分配是由 Python 內(nèi)存管理器按需通過本文檔中列出的 Python/C API 函數(shù)進(jìn)行的。
為了避免內(nèi)存破壞,擴(kuò)展的作者永遠(yuǎn)不應(yīng)該試圖用 C 庫函數(shù)導(dǎo)出的函數(shù)來對 Python 對象進(jìn)行操作,這些函數(shù)包括: malloc(), calloc(), realloc() 和 free()。這將導(dǎo)致 C 分配器和 Python 內(nèi)存管理器之間的混用,引發(fā)嚴(yán)重后果,這是由于它們實(shí)現(xiàn)了不同的算法,并在不同的堆上操作。但是,我們可以安全地使用 C 庫分配器為單獨(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;
在這個例子中,I/O 緩沖區(qū)的內(nèi)存請求是由 C 庫分配器處理的。Python 內(nèi)存管理器只參與了分配作為結(jié)果返回的字節(jié)對象。
In most situations, however, it is recommended to allocate memory from the Python heap specifically because the latter is under control of the Python memory manager. For example, this is required when the interpreter is extended with new object types written in C. Another reason for using the Python heap is the desire to inform the Python memory manager about the memory needs of the extension module. Even when the requested memory is used exclusively for internal, highly specific purposes, delegating all memory requests to the Python memory manager causes the interpreter to have a more accurate image of its memory footprint as a whole. Consequently, under certain circumstances, the Python memory manager may or may not trigger appropriate actions, like garbage collection, memory compaction or other preventive procedures. Note that by using the C library allocator as shown in the previous example, the allocated memory for the I/O buffer escapes completely the Python memory manager.
參見
環(huán)境變量 PYTHONMALLOC 可被用來配置 Python 所使用的內(nèi)存分配器。
環(huán)境變量 PYTHONMALLOCSTATS 可以用來在每次創(chuàng)建和關(guān)閉新的 pymalloc 對象區(qū)域時(shí)打印 pymalloc 內(nèi)存分配器 的統(tǒng)計(jì)數(shù)據(jù)。
分配器域
所有分配函數(shù)都屬于三個不同的“分配器域”之一(見 PyMemAllocatorDomain)。這些域代表了不同的分配策略,并為不同目的進(jìn)行了優(yōu)化。每個域如何分配內(nèi)存和每個域調(diào)用哪些內(nèi)部函數(shù)的具體細(xì)節(jié)被認(rèn)為是實(shí)現(xiàn)細(xì)節(jié),但是出于調(diào)試目的,可以在 此處 找到一張簡化的表格。沒有硬性要求將屬于給定域的分配函數(shù)返回的內(nèi)存,僅用于該域提示的目的(雖然這是推薦的做法)。例如,你可以將 PyMem_RawMalloc() 返回的內(nèi)存用于分配 Python 對象,或者將 PyObject_Malloc() 返回的內(nèi)存用作緩沖區(qū)。
三個分配域分別是:
原始域:用于為通用內(nèi)存緩沖區(qū)分配內(nèi)存,分配*必須*轉(zhuǎn)到系統(tǒng)分配器并且分配器可以在沒有 GIL 的情況下運(yùn)行。內(nèi)存直接請求自系統(tǒng)。
“Mem” 域:用于為 Python 緩沖區(qū)和通用內(nèi)存緩沖區(qū)分配內(nèi)存,分配時(shí)必須持有 GIL。內(nèi)存取自于 Python 私有堆。
對象域:用于分配屬于 Python 對象的內(nèi)存。內(nèi)存取自于 Python 私有堆。
當(dāng)釋放屬于給定域的分配函數(shù)先前分配的內(nèi)存時(shí),必須使用對應(yīng)的釋放函數(shù)。例如,PyMem_Free() 來釋放 PyMem_Malloc() 分配的內(nèi)存。
原始內(nèi)存接口
以下函數(shù)集封裝了系統(tǒng)分配器。這些函數(shù)是線程安全的,不需要持有 全局解釋器鎖。
default raw memory allocator 使用這些函數(shù):malloc()、 calloc()、 realloc() 和 free();申請零字節(jié)時(shí)則調(diào)用 malloc(1) (或 calloc(1, 1))
3.4 新版功能.
void *PyMem_RawMalloc(size_t n)
Allocates n bytes and returns a pointer of type void* to the allocated memory, or NULL if the request fails.
請求零字節(jié)可能返回一個獨(dú)特的非 NULL 指針,就像調(diào)用了 PyMem_RawMalloc(1) 一樣。但是內(nèi)存不會以任何方式被初始化。
void *PyMem_RawCalloc(size_t nelem, size_t elsize)
Allocates nelem elements each whose size in bytes is elsize and returns a pointer of type void* to the allocated memory, or NULL if the request fails. The memory is initialized to zeros.
請求零字節(jié)可能返回一個獨(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)存塊大小會被調(diào)整,但不會被釋放,返回非 NULL 指針。
除非 p 是 NULL ,否則它必須是之前調(diào)用 PyMem_RawMalloc() 、 PyMem_RawRealloc() 或 PyMem_RawCalloc() 所返回的。
如果請求失敗,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)用過的情況下,未定義的行為會發(fā)生。
如果 p 是 NULL, 那么什么操作也不會進(jìn)行。
內(nèi)存接口
以下函數(shù)集,仿照 ANSI C 標(biāo)準(zhǔn),并指定了請求零字節(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.
Allocates n bytes and returns a pointer of type void* to the allocated memory, or NULL if the request fails.
請求零字節(jié)可能返回一個獨(dú)特的非 NULL 指針,就像調(diào)用了 PyMem_Malloc(1) 一樣。但是內(nèi)存不會以任何方式被初始化。
void *PyMem_Calloc(size_t nelem, size_t elsize)
Part of the Stable ABI since version 3.7.
Allocates nelem elements each whose size in bytes is elsize and returns a pointer of type void* to the allocated memory, or NULL if the request fails. The memory is initialized to zeros.
請求零字節(jié)可能返回一個獨(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)存塊大小會被調(diào)整,但不會被釋放,返回非 NULL 指針。
除非 p 是 NULL ,否則它必須是之前調(diào)用 PyMem_Malloc() 、 PyMem_Realloc() 或 PyMem_Calloc() 所返回的。
如果請求失敗,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)用過的情況下,未定義的行為會發(fā)生。
如果 p 是 NULL, 那么什么操作也不會進(jìn)行。
以下面向類型的宏為方便而提供。 注意 TYPE 可以指任何 C 類型。
TYPE *PyMem_New(TYPE, size_t n)
Same as PyMem_Malloc(), but allocates (n * sizeof(TYPE)) bytes of memory. Returns a pointer cast to TYPE*. The memory will not have been initialized in any way.
TYPE *PyMem_Resize(void *p, TYPE, size_t n)
Same as PyMem_Realloc(), but the memory block is resized to (n * sizeof(TYPE)) bytes. Returns a pointer cast to TYPE*. On return, p will be a pointer to the new memory area, or NULL in the event of failure.
這是一個 C 預(yù)處理宏, p 總是被重新賦值。請保存 p 的原始值,以避免在處理錯誤時(shí)丟失內(nèi)存。
void PyMem_Del(void *p)
與 PyMem_Free() 相同
此外,我們還提供了以下宏集用于直接調(diào)用 Python 內(nèi)存分配器,而不涉及上面列出的 C API 函數(shù)。但是請注意,使用它們并不能保證跨 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)
對象分配器
以下函數(shù)集,仿照 ANSI C 標(biāo)準(zhǔn),并指定了請求零字節(jié)時(shí)的行為,可用于從Python堆分配和釋放內(nèi)存。
備注
當(dāng)通過 自定義內(nèi)存分配器 部分描述的方法攔截該域中的分配函數(shù)時(shí),無法保證這些分配器返回的內(nèi)存可以被成功地轉(zhuǎn)換成 Python 對象。
默認(rèn)對象分配器 使用 pymalloc 內(nèi)存分配器.
警告
在使用這些函數(shù)時(shí),必須持有 全局解釋器鎖(GIL) 。
void *PyObject_Malloc(size_t n)
Part of the Stable ABI.
Allocates n bytes and returns a pointer of type void* to the allocated memory, or NULL if the request fails.
請求零字節(jié)可能返回一個獨(dú)特的非 NULL 指針,就像調(diào)用了 PyObject_Malloc(1) 一樣。但是內(nèi)存不會以任何方式被初始化。
void *PyObject_Calloc(size_t nelem, size_t elsize)
Part of the Stable ABI since version 3.7.
Allocates nelem elements each whose size in bytes is elsize and returns a pointer of type void* to the allocated memory, or NULL if the request fails. The memory is initialized to zeros.
請求零字節(jié)可能返回一個獨(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)存塊大小會被調(diào)整,但不會被釋放,返回非 NULL 指針。
除非 p 是 NULL ,否則它必須是之前調(diào)用 PyObject_Malloc() 、 PyObject_Realloc() 或 PyObject_Calloc() 所返回的。
如果請求失敗,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)用過的情況下,未定義行為會發(fā)生。
如果 p 是 NULL, 那么什么操作也不會進(jìn)行。
默認(rèn)內(nèi)存分配器
默認(rèn)內(nèi)存分配器:
|
配置 |
名稱 |
PyMem_RawMalloc |
PyMem_Malloc |
PyObject_Malloc |
|---|---|---|---|---|
說明:
名稱:PYTHONMALLOC 環(huán)境變量的值。
malloc:來自 C 標(biāo)準(zhǔn)庫的系統(tǒng)分配器,C 函數(shù):malloc()、calloc()、realloc()和free()。pymalloc:pymalloc 內(nèi)存分配器.“+ debug”: 附帶 Python 內(nèi)存分配器的調(diào)試鉤子.
“調(diào)試構(gòu)建”:調(diào)試模式下的 Python 構(gòu)建。
自定義內(nèi)存分配器
3.4 新版功能.
type PyMemAllocatorEx
用于描述內(nèi)存塊分配器的結(jié)構(gòu)體。 該結(jié)構(gòu)體下列字段:
|
域 |
含意 |
|---|---|
在 3.5 版更改: The PyMemAllocator structure was renamed to PyMemAllocatorEx and a new calloc field was added.
type PyMemAllocatorDomain
用來識別分配器域的枚舉類。域有:
PYMEM_DOMAIN_RAW
函數(shù)
PyMem_RawMalloc()
PyMem_RawRealloc()
PyMem_RawCalloc()
PyMem_RawFree()
PYMEM_DOMAIN_MEM
函數(shù)
PyMem_Malloc(),
PyMem_Realloc()
PyMem_Calloc()
PyMem_Free()
PYMEM_DOMAIN_OBJ
函數(shù)
PyObject_Malloc()
PyObject_Realloc()
PyObject_Calloc()
PyObject_Free()
void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
獲取指定域的內(nèi)存塊分配器。
void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
設(shè)置指定域的內(nèi)存塊分配器。
當(dāng)請求零字節(jié)時(shí),新的分配器必須返回一個獨(dú)特的非 NULL 指針。
對于 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.
警告
PyMem_SetAllocator() does have the following contract:
It can be called after Py_PreInitialize() and before Py_InitializeFromConfig() to install a custom memory allocator. There are no restrictions over the installed allocator other than the ones imposed by the domain (for instance, the Raw Domain allows the allocator to be called without the GIL held). See the section on allocator domains for more information.
If called after Python has finish initializing (after Py_InitializeFromConfig() has been called) the allocator must wrap the existing allocator. Substituting the current allocator for some other arbitrary one is not supported.
void PyMem_SetupDebugHooks(void)
設(shè)置 Python 內(nèi)存分配器的調(diào)試鉤子 以檢測內(nèi)存錯誤。
Python 內(nèi)存分配器的調(diào)試鉤子
當(dāng) Python 在調(diào)試模式下構(gòu)建,PyMem_SetupDebugHooks() 函數(shù)在 Python 預(yù)初始化 時(shí)被調(diào)用,以在 Python 內(nèi)存分配器上設(shè)置調(diào)試鉤子以檢測內(nèi)存錯誤。
PYTHONMALLOC 環(huán)境變量可被用于在以發(fā)行模式下編譯的 Python 上安裝調(diào)試鉤子(例如:PYTHONMALLOC=debug)。
PyMem_SetupDebugHooks() 函數(shù)可被用于在調(diào)用了 PyMem_SetAllocator() 之后設(shè)置調(diào)試鉤子。
這些調(diào)試鉤子用特殊的、可辨認(rèn)的位模式填充動態(tài)分配的內(nèi)存塊。新分配的內(nèi)存用字節(jié) 0xCD``(``PYMEM_CLEANBYTE)填充,釋放的內(nèi)存用字節(jié) 0xDD``(``PYMEM_DEADBYTE)填充。內(nèi)存塊被填充了字節(jié) 0xFD``(``PYMEM_FORBIDDENBYTE)的“禁止字節(jié)”包圍。這些字節(jié)串不太可能是合法的地址、浮點(diǎn)數(shù)或ASCII字符串
運(yùn)行時(shí)檢查:
檢測對 API 的違反。例如:檢測對 PyMem_Malloc() 分配的內(nèi)存塊調(diào)用 PyObject_Free()。
檢測緩沖區(qū)起始位置前的寫入(緩沖區(qū)下溢)。
檢測緩沖區(qū)終止位置后的寫入(緩沖區(qū)溢出)。
檢測當(dāng)調(diào)用
PYMEM_DOMAIN_OBJ(如: PyObject_Malloc()) 和PYMEM_DOMAIN_MEM(如: PyMem_Malloc()) 域的分配器函數(shù)時(shí) GIL 已被持有。
在出錯時(shí),調(diào)試鉤子使用 tracemalloc 模塊來回溯內(nèi)存塊被分配的位置。只有當(dāng) tracemalloc 正在追蹤 Python 內(nèi)存分配,并且內(nèi)存塊被追蹤時(shí),才會顯示回溯。
讓 S = sizeof(size_t)。 將 2*S 個字節(jié)添加到每個被請求的 N 字節(jié)數(shù)據(jù)塊的兩端。 內(nèi)存的布局像是這樣,其中 p 代表由類似 malloc 或類似 realloc 的函數(shù)所返回的地址 (p[i:j] 表示從 *(p+i) 左側(cè)開始到 *(p+j) 左側(cè)止的字節(jié)數(shù)據(jù)切片;請注意對負(fù)索引號的處理與 Python 切片是不同的):
p[-2*S:-S]
最初所要求的字節(jié)數(shù)。 這是一個 size_t,為大端序(易于在內(nèi)存轉(zhuǎn)儲中讀?。?。
p[-S]
API 標(biāo)識符(ASCII 字符):
'r'表示PYMEM_DOMAIN_RAW。'm'表示PYMEM_DOMAIN_MEM。'o'表示PYMEM_DOMAIN_OBJ。
p[-S+1:0]
PYMEM_FORBIDDENBYTE 的副本。 用于捕獲下層的寫入和讀取。
p[0:N]
所請求的內(nèi)存,用 PYMEM_CLEANBYTE 的副本填充,用于捕獲對未初始化內(nèi)存的引用。 當(dāng)調(diào)用 realloc 之類的函數(shù)來請求更大的內(nèi)存塊時(shí),額外新增的字節(jié)也會用 PYMEM_CLEANBYTE 來填充。 當(dāng)調(diào)用 free 之類的函數(shù)時(shí),這些字節(jié)會用 PYMEM_DEADBYTE 來重寫,以捕獲對已釋放內(nèi)存的引用。 當(dāng)調(diào)用 realloc 之類的函數(shù)來請求更小的內(nèi)存塊時(shí),多余的舊字節(jié)也會用 PYMEM_DEADBYTE 來填充。
p[N:N+S]
PYMEM_FORBIDDENBYTE 的副本。 用于捕獲超限的寫入和讀取。
p[N+S:N+2*S]
僅當(dāng)定義了 PYMEM_DEBUG_SERIALNO 宏時(shí)會被使用(默認(rèn)情況下將不定義)。
一個序列號,每次調(diào)用 malloc 之類或 realloc 之類的函數(shù)時(shí)自增 1。 大端序的 size_t。 如果之后檢測到了“被破壞的內(nèi)存”,此序列號提供了一個很好的手段用來在下次運(yùn)行時(shí)設(shè)置中斷點(diǎn),以捕獲該內(nèi)存塊被破壞的瞬間。 obmalloc.c 中的靜態(tài)函數(shù) bumpserialno() 是此序列號會發(fā)生自增的唯一地方,它的存在使你可以方便地設(shè)置這樣的中斷點(diǎn)。
一個 realloc 之類或 free 之類的函數(shù)會先檢查兩端的 PYMEM_FORBIDDENBYTE 字節(jié)是否完好。 如果它們被改變了,則會將診斷輸出寫入到 stderr,并且程序?qū)⑼ㄟ^ Py_FatalError() 中止。 另一種主要的失敗模式是當(dāng)程序讀到某種特殊的比特模式并試圖將其用作地址時(shí)觸發(fā)內(nèi)存錯誤。 如果你隨即進(jìn)入調(diào)試器并查看該對象,你很可能會看到它已完全被填充為 PYMEM_DEADBYTE (意味著已釋放的內(nèi)存被使用) 或 PYMEM_CLEANBYTE (意味著未初始貨攤內(nèi)存被使用)。
在 3.6 版更改: PyMem_SetupDebugHooks() 函數(shù)現(xiàn)在也能在使用發(fā)布模式編譯的 Python 上工作。 當(dāng)發(fā)生錯誤時(shí),調(diào)試鉤子現(xiàn)在會使用 tracemalloc 來獲取已分配內(nèi)存塊的回溯信息。 調(diào)試鉤子現(xiàn)在還會在 PYMEM_DOMAIN_OBJ 和 PYMEM_DOMAIN_MEM 作用域的函數(shù)被調(diào)用時(shí)檢查是否持有 GIL。
在 3.8 版更改: 字節(jié)模式 0xCB (PYMEM_CLEANBYTE)、 0xDB (PYMEM_DEADBYTE) 和 0xFB (PYMEM_FORBIDDENBYTE) 已被 0xCD 、 0xDD 和 0xFD 替代以使用與 Windows CRT 調(diào)試 malloc() 和 free() 相同的值。
pymalloc 分配器
Python 有為具有短生命周期的小對象(小于或等于 512 字節(jié))優(yōu)化的 pymalloc 分配器。它使用固定大小為 256 KiB 的稱為 “arenas” 的內(nèi)存映射。對于大于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()。
如果 Python 配置了 --without-pymalloc 選項(xiàng),那么此分配器將被禁用。也可以在運(yùn)行時(shí)使用 PYTHONMALLOC`(例如:``PYTHONMALLOC=malloc`)環(huán)境變量來禁用它。
自定義 pymalloc Arena 分配器
3.4 新版功能.
type PyObjectArenaAllocator
用來描述一個 arena 分配器的結(jié)構(gòu)體。這個結(jié)構(gòu)體有三個字段:
|
域 |
含意 |
|---|---|
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 模塊中跟蹤一個已分配的內(nèi)存塊。
成功時(shí)返回 0,出錯時(shí)返回 -1 (無法分配內(nèi)存來保存跟蹤信息)。 如果禁用了 tracemalloc 則返回 -2。
如果內(nèi)存塊已被跟蹤,則更新現(xiàn)有跟蹤信息。
int PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
在 tracemalloc 模塊中取消跟蹤一個已分配的內(nèi)存塊。 如果內(nèi)存塊未被跟蹤則不執(zhí)行任何操作。
如果 tracemalloc 被禁用則返回 -2,否則返回 0。
例子
以下是來自 概述 小節(jié)的示例,經(jīng)過重寫以使 I/O 緩沖區(qū)是通過使用第一個函數(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ū)總是通過歸屬于相同集的函數(shù)來操縱的。 事實(shí)上,對于一個給定的內(nèi)存塊必須使用相同的內(nèi)存 API 族,以便使得混合不同分配器的風(fēng)險(xiǎn)減至最低。 以下代碼序列包含兩處錯誤,其中一個被標(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() */
除了旨在處理來自 Python 堆的原始內(nèi)存塊的函數(shù)之外, Python 中的對象是通過 PyObject_New(), PyObject_NewVar() 和 PyObject_Del() 來分配和釋放的。
這些將在有關(guān)如何在 C 中定義和實(shí)現(xiàn)新對象類型的下一章中講解。
網(wǎng)站名稱:創(chuàng)新互聯(lián)Python教程:內(nèi)存管理
路徑分享:http://www.dlmjj.cn/article/cohhieg.html


咨詢
建站咨詢
