-
1 # 你看我獨角獸嗎
-
2 # 不平常的芝麻
Python管理記憶體:
python官網:https://docs.python.org/3.5/c-api/memory.html
python3.5版本
Memory Management
Overview
Python中的記憶體管理涉及包含所有Python物件和資料結構的私有堆。此私有堆的管理由Python記憶體管理器在內部確保。Python記憶體管理器有不同的元件,它們處理各種動態儲存管理方面,如共享,分段,預分配或快取。
在最底層,原始記憶體分配器確保私有堆中有足夠的空間透過與作業系統的記憶體管理器互動來儲存所有與Python相關的資料。在原始記憶體分配器之上,幾個特定於物件的分配器在同一個堆上操作,並實現適合於每個物件型別的特性的不同的記憶體管理策略。例如,整數物件在堆中的管理方式與字串,元組或字典不同,因為整數意味著不同的儲存要求和速度/空間權衡。Python記憶體管理器因此將一些工作委託給特定於物件的分配器,但確保後者在私有堆的邊界內操作。
重要的是要理解Python堆的管理由直譯器本身執行,並且使用者不能控制它,即使她經常操縱到該堆內部的記憶體塊的物件指標。Python記憶體管理器透過本文件中列出的Python / C API函式根據需要執行Python物件和其他內部緩衝區的堆空間分配。
為了避免記憶體損壞,擴充套件編寫器不應嘗試對C庫匯出的函式操作Python物件:malloc(),calloc(),realloc()和free()。這將導致C分配器和Python記憶體管理器之間的混合呼叫具有致命後果,因為它們實現不同的演算法並對不同的堆執行操作。但是,可以使用C庫分配器為單獨的目的安全地分配和釋放記憶體塊,如以下示例所示:
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緩衝器的儲存器請求由C庫分配器處理。Python記憶體管理器僅涉及作為結果返回的字串物件的分配。
然而,在大多數情況下,建議從Python堆分配記憶體,特別是因為後者在Python記憶體管理器的控制下。例如,當直譯器使用以C編寫的新物件型別擴充套件時,這是必需的。使用Python堆的另一個原因是希望通知 Python記憶體管理器有關擴充套件的記憶體需求模組。即使當所請求的儲存器專門用於內部的高度特定目的時,將所有儲存器請求委託給Python儲存器管理器也會導致直譯器作為整體具有更準確的其儲存器佔用的映像。因此,在某些情況下,Python記憶體管理器可能或可能不會觸發適當的操作,如垃圾容器,記憶體壓縮或其他預防性過程。注意,透過使用C庫分配器,如前面的例子所示,為I / O緩衝區分配的記憶體完全轉儲Python記憶體管理器。
也可以看看 PYTHONMALLOCSTATS環境變數可用於在建立新物件競技場時和關閉時列印記憶體分配統計資訊。
Raw Memory Interface
以下函式集是系統分配器的包裝器。這些函式是執行緒安全的,GIL不需要保持。
The default raw memory block allocator uses the following functions: malloc(), calloc(), realloc() and free(); call malloc(1) (or calloc(1, 1)) when requesting zero bytes.
版本3.4中的新功能。
void* PyMem_RawMalloc(size_t n)
分配n位元組,如果請求失敗,則返回型別為void*的指標到分配的記憶體,或NULL。
如果可能,請求零位元組返回一個明確的非NULL指標,如同PyMem_RawMalloc(1)被呼叫。記憶體不會以任何方式初始化。
void* PyMem_RawCalloc(size_t nelem, size_t elsize)
分配位元組大小為elsize的nelem元素,並將void*型別的指標返回到分配的記憶體,或NULL 如果請求失敗。儲存器初始化為零。
如果可能,請求零大小零元素或零大小的元素返回一個非NULL指標,如同PyMem_RawCalloc(1, 1) t3 >。
版本3.5中的新功能。
void* PyMem_RawRealloc(void *p, size_t n)
調整p指向n位元組指向的儲存器塊大小。內容將不變為舊和新尺寸的最小值。
如果p是NULL,則該呼叫相當於PyMem_RawMalloc(n);否則如果n等於零,則調整儲存器塊的大小,但不釋放,返回的指標為非NULL。
Unless p is NULL, it must have been returned by a previous call to PyMem_RawMalloc(), PyMem_RawRealloc() or PyMem_RawCalloc().
如果請求失敗,PyMem_RawRealloc()返回NULL和p仍然是前一個記憶體區域的有效指標。
void PyMem_RawFree(void *p)
Frees the memory block pointed to by p, which must have been returned by a previous call to PyMem_RawMalloc(), PyMem_RawRealloc() or PyMem_RawCalloc(). 否則,或者如果PyMem_Free(p)之前被呼叫,則發生未定義的行為。
如果p為NULL,則不執行操作。
Memory Interface
以下函式設定,建模在ANSI C標準之後,但指定請求零位元組時的行為,可用於從Python堆分配和釋放記憶體。
The default memory block allocator uses the following functions: malloc(), calloc(), realloc() and free(); call malloc(1) (or calloc(1, 1)) when requesting zero bytes.
警告使用這些功能時,必須保持GIL。
void* PyMem_Malloc(size_t n)
如果請求失敗,則分配n位元組,並向分配的記憶體返回型別為void*的指標,或返回NULL。
如果可能,請求零位元組返回一個明確的非NULL指標,如同已經呼叫PyMem_Malloc(1)。記憶體不會以任何方式初始化。
void* PyMem_Calloc(size_t nelem, size_t elsize)
分配位元組大小為elsize的nelem元素,並將void*型別的指標返回到分配的記憶體,或NULL 如果請求失敗。儲存器初始化為零。
如果可能,請求零大小零元素或大小零位元組的元素返回一個明確的非NULL指標,如同PyMem_Calloc(1, 1) t3 >。
版本3.5中的新功能。
void* PyMem_Realloc(void *p, size_t n)
調整p指向n位元組指向的儲存器塊大小。內容將不變為舊和新尺寸的最小值。
如果p是NULL,則呼叫相當於PyMem_Malloc(n);否則如果n等於零,則調整儲存器塊的大小,但不釋放,返回的指標為非NULL。
Unless p is NULL, it must have been returned by a previous call to PyMem_Malloc(), PyMem_Realloc() or PyMem_Calloc().
如果請求失敗,PyMem_Realloc()返回NULL和p仍然是前一個記憶體區域的有效指標。
void PyMem_Free(void *p)
Frees the memory block pointed to by p, which must have been returned by a previous call to PyMem_Malloc(), PyMem_Realloc() or PyMem_Calloc(). 否則,或者如果PyMem_Free(p)之前被呼叫,則發生未定義的行為。
如果p為NULL,則不執行操作。
為方便起見,提供了以下面向面向的宏。請注意,TYPE是指任何C型別。
TYPE* PyMem_New(TYPE, size_t n)
與PyMem_Malloc()相同,但分配(n * sizeof(TYPE)) t3 >位元組的記憶體。返回一個轉換為TYPE*的指標。記憶體不會以任何方式初始化。
TYPE* PyMem_Resize(void *p, TYPE, size_t n)
與PyMem_Realloc()相同,但是記憶體塊調整為(n * sizeof(TYPE) t6>位元組。返回一個轉換為TYPE*的指標。返回時,p將是指向新儲存區的指標,或者在發生故障時NULL。
這是一個C預處理器宏; p總是重新分配。儲存p的原始值以避免在處理錯誤時丟失記憶體。
void PyMem_Del(void *p)
與PyMem_Free()相同。
此外,提供以下宏集直接呼叫Python記憶體分配器,而不涉及上面列出的C API函式。但是,請注意,它們的使用不保留跨Python版本的二進位制相容性,因此在擴充套件模組中已被棄用。
PyMem_MALLOC(size)
PyMem_NEW(type, size)
PyMem_REALLOC(ptr, size)
PyMem_RESIZE(ptr, type, size)
PyMem_FREE(ptr)
PyMem_DEL(ptr)
Customize Memory Allocators
版本3.4中的新功能。
PyMemAllocatorEx
用於描述記憶體塊分配器的結構。該結構有四個欄位:
在版本3.5中已更改: PyMemAllocator結構已重新命名為PyMemAllocatorEx,並添加了新的calloc欄位。
PyMemAllocatorDomain
用於標識分配器域的列舉。域:
PYMEM_DOMAIN_RAW: functions PyMem_RawMalloc(), PyMem_RawRealloc(), PyMem_RawCalloc() and PyMem_RawFree()
PYMEM_DOMAIN_MEM: functions PyMem_Malloc(), PyMem_Realloc(), PyMem_Calloc() and PyMem_Free()
PYMEM_DOMAIN_OBJ:functions PyObject_Malloc(),PyObject_Realloc(),PyObject_Calloc()和PyObject_Free()
void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
獲取指定域的記憶體塊分配器。
void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
設定指定域的記憶體塊分配器。
當請求零位元組時,新的分配器必須返回一個不同的非空指標。
對於PYMEM_DOMAIN_RAW域,分配器必須是執行緒安全的:呼叫分配器時,GIL不會保持。
如果新的分配器不是一個鉤子(不呼叫前面的分配器),必須呼叫PyMem_SetupDebugHooks()函式重新安裝除錯鉤子在新的分配器。
void PyMem_SetupDebugHooks(void)
設定掛鉤以檢測以下Python記憶體分配器函式中的錯誤:
PyMem_RawMalloc(),PyMem_RawRealloc(),PyMem_RawCalloc(),PyMem_RawFree()
PyMem_Malloc(),PyMem_Realloc(),PyMem_Calloc(),PyMem_Free()
PyObject_Malloc(),PyObject_Realloc(),PyObject_Calloc(),PyObject_Free()
新分配的記憶體用位元組0xCB填充,釋放的記憶體用位元組0xDB填充。附加檢查:
detect API violations, ex: PyObject_Free() called on a buffer allocated by PyMem_Malloc()
在緩衝區開始之前檢測寫(緩衝區下溢)
檢測寫緩衝區結束後(緩衝區溢位)
如果Python沒有被編譯為除錯模式,該函式不執行任何操作。
Customize PyObject Arena Allocator
對於小於512位元組的分配,Python有一個pymalloc分配器。這個分配器針對壽命短的小物件進行了最佳化。它使用固定大小為256 KB的稱為“arenas”的記憶體對映。對於大於512位元組的分配,它返回到PyMem_RawMalloc()和PyMem_RawRealloc()。pymalloc是PyObject_Malloc()使用的預設分配器。
預設的競技場分配器使用以下功能:
VirtualAlloc()和VirtualFree()
mmap()和munmap()如果可用,
malloc()和free()。
版本3.4中的新功能。
PyObjectArenaAllocator
用於描述競技場分配器的結構。該結構有三個欄位:
PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)
獲取競技場分配器。
PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)
設定競技場分配器。
Examples
這是從Overview部分的示例,重寫,以便使用第一個函式集從Python堆分配I / O緩衝區:
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;
相同的程式碼使用面向型別的函式集:
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;
注意,在上面的兩個例子中,緩衝區總是透過屬於同一集合的函式來操作。實際上,對於給定的儲存器塊,需要使用相同的儲存器API族,使得將不同分配器混合的風險降低到最小。以下程式碼序列包含兩個錯誤,其中一個標記為fatal,因為它混合了在不同堆上操作的兩個不同的分配器。
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堆的原始記憶體塊的函式之外,Python中的物件還透過PyObject_New(),PyObject_NewVar()和PyObject_Del()。
這些將在下一章中關於在C中定義和實現新的物件型別進行解釋。
在推薦一個python記憶體管理的網址
https://realpython.com/python-memory-management/#memory-management-from-hardware-to-software
Memory Management in Python
-
3 # 網際網路技術小站
Python是透過引入了一個機制:引用計數,來進行管理記憶體。
python內部使用引用計數,來保持追蹤記憶體中的物件,Python內部記錄了物件有多少個引用,即引用計數,當物件被建立時就建立了一個引用計數,當物件不再需要時,這個物件的引用計數為0時,它被垃圾回收。
-
4 # 馨滿溢足的家
一、為什麼進行記憶體管理
先理解一下為什麼要進行記憶體管理,記憶體管理是指軟體執行時對計算機記憶體資源的分配和使用的技術。其最主要的目的是如何高效,快速的分配,並且在適當的時候釋放和回收記憶體資源。二、記憶體的分配方式
記憶體分配方式有四種:(1)從靜態儲存區域分配。記憶體在程式編譯的時候就已經分配好,存放全域性變數和靜態變數,這些記憶體在程式執行期間都存在。(2)在棧上建立。由編譯器自動分配自動釋放,用於存放區域性變數和引數,棧內的物件先進後出,所以先建立的物件會後析構。棧由於是編譯器自動管理的,所以棧內的物件不會存在記憶體洩露問題,並且效率很高,但是分配的記憶體容量有限。(3)從堆上分配,亦稱動態記憶體分配。程式設計師自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,但問題也最多。(4)常量區:存放常量字串,程式結束後由系統釋放
三、python是怎麼管理記憶體的:
python的記憶體管理是由私有的heap空間管理的,所有的python物件和資料結構都在一個專有的heap(堆),程式設計師沒有訪問該heap的許可權,只有直譯器才能對他進行操作。而python的heap空間分配是由記憶體管理模組進行的,其核心API會提供一些訪問該模組的方法提供程式設計師使用。python自帶的垃圾回收系統,它會回收並釋放沒有被使用的記憶體,讓她們能夠被其他程式使用(記憶體池。被釋放後先回到記憶體池然後再被別的程式所運用)
回覆列表
在最低級別,原始記憶體分配器確保堆中有足夠的空間透過與作業系統的記憶體管理器互動來儲存所有與Python相關的資料。在原始記憶體分配器之上,幾個特定於物件的分配器在同一堆上執行,並實現適合於每種物件型別的特性的不同記憶體管理策略。
例如,整數物件在堆內的管理方式與字串,元組或字典不同,因為整數意味著不同的儲存要求和速度/空間權衡。因此,Python記憶體管理器將一些工作委託給特定於物件的分配器,但確保後者在堆的邊界內執行。
重要的是要理解Python堆的管理是由直譯器本身執行的,並且使用者無法控制它,即使它們經常操作物件指標到該堆內的記憶體塊。 Python記憶體管理器透過本文件中列出的Python / C API函式按需執行Python物件和其他內部緩衝區的堆空間分配。
為了避免記憶體損壞,擴充套件編寫器不應該嘗試使用C庫匯出的函式對Python物件進行操作:malloc(),calloc(),realloc()和free()。這將導致C分配器和Python記憶體管理器之間的混合呼叫帶來致命的後果,因為它們實現了不同的演算法並在不同的堆上執行。
在大多數情況下,我們建議從Python堆中分配記憶體,因為後者受Python記憶體管理器的控制。 例如,當使用C編寫的新物件型別擴充套件直譯器時,這是必需的。使用Python堆的另一個原因是希望通知Python記憶體管理器有關擴充套件模組的記憶體需求。 可將所有記憶體請求委託給Python記憶體管理器也會使直譯器整體上有更準確的記憶體佔用空間。 所以在某些情況下,Python記憶體管理器可能會或可能不會觸發適當的操作,如垃圾收集,記憶體壓縮等。