Memory Management¶
Overview¶
Python manages memory through a private heap that contains all Python objects and data structures. The Python memory manager handles sharing, segmentation, preallocation, and caching internally.
- Raw Memory Allocator: Interfaces directly with the operating system to ensure sufficient space in the private heap.
- Object-specific Allocators: Operate on top of the raw allocator, implementing policies tailored to specific object types (e.g., integers vs. dictionaries).
- Internal Control: The interpreter manages the heap automatically. Extension writers should use the provided C API functions rather than standard C library functions to ensure the interpreter accurately tracks its memory footprint.
The Three Allocation Domains¶
Every allocation function in the Python C API belongs to one of three domains. You must use the same domain for both allocation and deallocation of a specific block.
| Domain | Purpose | Thread State Required? | Primary Functions |
|---|---|---|---|
| Raw | General-purpose buffers; system-level allocation. | No | PyMem_RawMalloc, PyMem_RawFree |
| Mem | Internal Python buffers and general-purpose heap memory. | Yes | PyMem_Malloc, PyMem_Free |
| Object | Allocation specifically for Python objects. | Yes | PyObject_Malloc, PyObject_Free |
Note for Free-Threaded Builds: In free-threaded versions of Python, it is a hard requirement that Python objects are allocated exclusively using the Object domain. General buffers must use the Raw or Mem domains.
API Reference¶
Raw Memory Interface¶
These functions are wrappers for the system allocator and are safe to call without holding the Global Interpreter Lock (GIL) or having an attached thread state.
void *PyMem_RawMalloc(size_t n): Allocatesnbytes. ReturnsNULLon failure.void *PyMem_RawCalloc(size_t nelem, size_t elsize): Allocates memory for an array and initializes it to zeros.void *PyMem_RawRealloc(void *p, size_t n): Resizes a previously allocated block.void PyMem_RawFree(void *p): Releases memory allocated via the Raw domain.
Memory Interface (Standard)¶
These functions use the pymalloc allocator by default. They require an attached thread state.
void *PyMem_Malloc(size_t n): Allocatesnbytes from the Python heap.void *PyMem_Free(void *p): Frees memory allocated viaPyMem_MallocorPyMem_Calloc.
Type-Oriented Macros:
PyMem_New(TYPE, n): Allocates(n * sizeof(TYPE))bytes and casts toTYPE*.PyMem_Resize(p, TYPE, n): Resizes the block tonelements ofTYPE.PyMem_Del(p): Alias forPyMem_Free.
Object Allocator¶
Optimized for small allocations (typically ≤ 512 bytes) using the pymalloc algorithm.
void *PyObject_Malloc(size_t n): Essential for creating new Python object types.void PyObject_Free(void *p): Must be used for any pointer returned byPyObject_Malloc.
Safety & Best Practices¶
The Cardinal Rule: Do Not Mix Allocators¶
Never mix standard C library functions (malloc, free) with Python memory manager functions for the same memory block.
- Wrong:
ptr = malloc(10); PyMem_Free(ptr);→ Crash/Corruption - Correct:
ptr = PyMem_Malloc(10); PyMem_Free(ptr);
Error Handling¶
Always check for NULL returns. If an allocation fails, you should typically return a Python exception.
Why use Python's Heap instead of malloc?¶
- Performance:
pymallocis often faster than the systemmallocfor small, frequent allocations. - Garbage Collection: Using the Mem/Object domains allows the interpreter to track the memory footprint, which can trigger garbage collection when memory pressure is high.
- Debugging: Python's debug hooks (enabled via
PYTHONMALLOC) can detect buffer overflows and memory leaks more effectively when using the official API.
Implementation Example¶
Recommended: Using the Python Heap¶
PyObject *example_function(PyObject *self, PyObject *args) {
PyObject *res;
// Allocate a buffer using the Python Mem domain
char *buf = PyMem_New(char, 512);
if (buf == NULL)
return PyErr_NoMemory();
// Perform operations...
res = PyBytes_FromString(buf);
// Clean up using the matching domain function
PyMem_Free(buf);
return res;
}