Документация Python неофициальный перевод

memory.md

385 строк · 37.4 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.9/c-api/memory.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Управление памятью89## Обзор1011Управление памятью в Python включает приватную кучу, содержащую все объекты и структуры данных Python. Управление этой приватной кучей внутренне обеспечивается *менеджером памяти Python*. Менеджер памяти Python имеет различные компоненты, которые занимаются разными аспектами управления динамической памятью, такими как совместное использование, сегментация, предварительное выделение или кеширование.1213На нижнем уровне сырой распределитель памяти гарантирует, что в приватной куче достаточно места для хранения всех данных Python, взаимодействуя с менеджером памяти операционной системы. Поверх сырого распределителя памяти несколько объектно-специфичных распределителей работают с той же кучей и реализуют различные политики управления памятью, адаптированные к особенностям каждого типа объектов. Например, целочисленные объекты управляются в куче иначе, чем строки, кортежи или словари, поскольку целые числа подразумевают другие требования к хранению и компромиссы между скоростью и объёмом. Таким образом, менеджер памяти Python делегирует часть работы объектно-специфичным распределителям, но следит, чтобы последние работали в границах приватной кучи.1415Важно понимать, что управление кучей Python выполняется самим интерпретатором, и пользователь не может на него повлиять, даже если регулярно манипулирует указателями на объекты в этой куче. Выделение памяти в куче для объектов Python и других внутренних буферов выполняется по требованию менеджером памяти Python через функции Python/C API, перечисленные в этом документе.1617Чтобы избежать повреждения памяти, разработчики расширений никогда не должны пытаться работать с объектами Python с помощью функций, экспортируемых библиотекой C: `malloc()`, `calloc()`, `realloc()` и `free()`. Это приведёт к смешанным вызовам между распределителем C и менеджером памяти Python с фатальными последствиями, поскольку они реализуют разные алгоритмы и работают с разными кучами. Однако можно безопасно выделять и освобождать блоки памяти с помощью распределителя библиотеки C для отдельных целей, как показано в следующем примере:1819```c20PyObject *res;21char *buf = (char *) malloc(BUFSIZ); /* для ввода-вывода */2223if (buf == NULL)24    return PyErr_NoMemory();25...Do some I/O operation involving buf...26res = PyBytes_FromString(buf);27free(buf); /* выделено через malloc */28return res;29```3031В этом примере запрос памяти для буфера ввода-вывода обрабатывается распределителем библиотеки C. Менеджер памяти Python участвует только в выделении объекта bytes, возвращаемого в результате.3233Однако в большинстве ситуаций рекомендуется выделять память из Python-кучи, поскольку она находится под управлением менеджера памяти Python. Например, это необходимо, когда интерпретатор расширяется новыми типами объектов, написанными на C. Ещё одна причина использовать Python-кучу – желание *информировать* менеджер памяти Python о потребностях модуля расширения в памяти. Даже если запрошенная память используется исключительно для внутренних, узкоспециализированных целей, передача всех запросов памяти менеджеру памяти Python позволяет интерпретатору получать более точную картину общего объёма используемой памяти. Как следствие, при определённых обстоятельствах менеджер памяти Python может запускать или не запускать соответствующие действия, такие как сборка мусора, уплотнение памяти или другие профилактические процедуры. Обратите внимание: при использовании аллокатора из библиотеки C, как показано в предыдущем примере, выделенная память для буфера ввода-вывода полностью уходит из-под контроля менеджера памяти Python.3435> **См. также**36>37> Переменная окружения [`PYTHONMALLOC`](https://python-all.ru/3.9/using/cmdline.html#envvar-PYTHONMALLOC) может использоваться для настройки распределителей памяти, используемых Python.38>39> Переменная окружения [`PYTHONMALLOCSTATS`](https://python-all.ru/3.9/using/cmdline.html#envvar-PYTHONMALLOCSTATS) может использоваться для вывода статистики [распределителя памяти pymalloc](https://python-all.ru/3.9/c-api/memory.html#pymalloc) каждый раз при создании новой арены объектов pymalloc, а также при завершении работы.4041## Сырой интерфейс памяти4243Следующие наборы функций являются обёртками вокруг системного аллокатора. Эти функции потокобезопасны, удерживать [GIL](https://python-all.ru/3.9/glossary.html#term-global-interpreter-lock) не требуется.4445[Стандартный сырой распределитель памяти](https://python-all.ru/3.9/c-api/memory.html#default-memory-allocators) использует следующие функции: `malloc()`, `calloc()`, `realloc()` и `free()`; вызывайте `malloc(1)` (или `calloc(1, 1)`) при запросе нулевого количества байтов.4647Новое в версии 3.4.4849#### `void* PyMem_RawMalloc(size_t n)`5051Выделяет *n* байт и возвращает указатель типа `void*` на выделенную память или `NULL`, если запрос не удался.5253Запрос нуля байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyMem_RawMalloc(1)`. Память не будет инициализирована каким-либо образом.5455#### `void* PyMem_RawCalloc(size_t nelem, size_t elsize)`5657Выделяет *nelem* элементов, каждый размером в байтах *elsize*, и возвращает указатель типа `void*` на выделенную память или `NULL`, если запрос не удался. Память инициализируется нулями.5859Запрос нулевого количества элементов или элементов размером ноль байтов возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо него был вызван `PyMem_RawCalloc(1, 1)`.6061Новое в версии 3.5.6263#### `void* PyMem_RawRealloc(void *p, size_t n)`6465Изменяет размер блока памяти, на который указывает *p*, до *n* байт. Содержимое останется неизменным в объеме, равном минимальному из старого и нового размеров.6667Если *p* равен `NULL`, вызов эквивалентен `PyMem_RawMalloc(n)`; иначе если *n* равен нулю, блок памяти изменяет размер, но не освобождается, и возвращаемый указатель отличен от `NULL`.6869Если *p* не равен `NULL`, он должен быть возвращен предыдущим вызовом [`PyMem_RawMalloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawMalloc), [`PyMem_RawRealloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawRealloc) или [`PyMem_RawCalloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawCalloc).7071В случае ошибки [`PyMem_RawRealloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawRealloc) возвращает `NULL`, и *p* остается действующим указателем на предыдущую область памяти.7273#### `void PyMem_RawFree(void *p)`7475Освобождает блок памяти, на который указывает *p*. Этот указатель должен быть возвращен предыдущим вызовом [`PyMem_RawMalloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawMalloc), [`PyMem_RawRealloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawRealloc) или [`PyMem_RawCalloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawCalloc). В противном случае, или если `PyMem_RawFree(p)` уже вызывался, поведение не определено.7677Если *p* равен `NULL`, то никаких действий не выполняется.7879## Интерфейс памяти8081Следующие наборы функций, основанные на стандарте ANSI C, но определяющие поведение при запросе нуля байт, доступны для выделения и освобождения памяти из кучи Python.8283[Аллокатор памяти по умолчанию](https://python-all.ru/3.9/c-api/memory.html#default-memory-allocators) использует [аллокатор памяти pymalloc](https://python-all.ru/3.9/c-api/memory.html#pymalloc).8485> **Предупреждение**86>87> При использовании этих функций необходимо удерживать [GIL](https://python-all.ru/3.9/glossary.html#term-global-interpreter-lock).8889Изменено в версии 3.6: Аллокатором по умолчанию теперь является pymalloc вместо системного `malloc()`.9091#### `void* PyMem_Malloc(size_t n)`9293Выделяет *n* байт и возвращает указатель типа `void*` на выделенную память или `NULL`, если запрос не удался.9495Запрос нуля байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyMem_Malloc(1)`. Память не будет инициализирована каким-либо образом.9697#### `void* PyMem_Calloc(size_t nelem, size_t elsize)`9899Выделяет *nelem* элементов, каждый размером в байтах *elsize*, и возвращает указатель типа `void*` на выделенную память или `NULL`, если запрос не удался. Память инициализируется нулями.100101Запрос нуля элементов или элементов размером ноль байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyMem_Calloc(1, 1)`.102103Новое в версии 3.5.104105#### `void* PyMem_Realloc(void *p, size_t n)`106107Изменяет размер блока памяти, на который указывает *p*, до *n* байт. Содержимое останется неизменным в пределах меньшего из старого и нового размеров.108109Если *p* равен `NULL`, вызов эквивалентен `PyMem_Malloc(n)`; в противном случае, если *n* равен нулю, размер блока памяти изменяется, но он не освобождается, и возвращаемый указатель не равен `NULL`.110111Если *p* не равен `NULL`, он должен быть возвращён предыдущим вызовом [`PyMem_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Malloc), [`PyMem_Realloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Realloc) или [`PyMem_Calloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Calloc).112113Если запрос не удался, [`PyMem_Realloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Realloc) возвращает `NULL`, а *p* остаётся корректным указателем на предыдущую область памяти.114115#### `void PyMem_Free(void *p)`116117Освобождает блок памяти, на который указывает *p*. Этот блок должен быть возвращён предыдущим вызовом [`PyMem_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Malloc), [`PyMem_Realloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Realloc) или [`PyMem_Calloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Calloc). В противном случае, или если до этого был вызван `PyMem_Free(p)`, поведение не определено.118119Если *p* равен `NULL`, то никаких действий не выполняется.120121Для удобства предоставлены следующие макросы, ориентированные на типы. Обратите внимание, что *TYPE* относится к любому типу C.122123#### `TYPE* PyMem_New(TYPE, size_t n)`124125То же, что и [`PyMem_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Malloc), но выделяет `(n * sizeof(TYPE))` байт памяти. Возвращает указатель, приведенный к `TYPE*`. Память не будет инициализирована каким-либо образом.126127#### `TYPE* PyMem_Resize(void *p, TYPE, size_t n)`128129То же, что [`PyMem_Realloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Realloc), но блок памяти изменяется до `(n * sizeof(TYPE))` байт. Возвращает указатель, приведённый к `TYPE*`. При возврате *p* будет указателем на новую область памяти или `NULL` в случае ошибки.130131Это макрос препроцессора C; *p* всегда переназначается. Сохраняйте исходное значение *p*, чтобы не потерять память при обработке ошибок.132133#### `void PyMem_Del(void *p)`134135То же, что и [`PyMem_Free()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Free).136137Кроме того, для прямого вызова аллокатора памяти Python, без использования перечисленных выше функций C API, предоставляются следующие наборы макросов. Однако следует учитывать, что их использование не гарантирует двоичной совместимости между версиями Python, поэтому в модулях расширения они считаются устаревшими.138139- `PyMem_MALLOC(size)`140- `PyMem_NEW(type, size)`141- `PyMem_REALLOC(ptr, size)`142- `PyMem_RESIZE(ptr, type, size)`143- `PyMem_FREE(ptr)`144- `PyMem_DEL(ptr)`145146## Аллокаторы объектов147148Следующие наборы функций, основанные на стандарте ANSI C, но определяющие поведение при запросе нуля байт, доступны для выделения и освобождения памяти из кучи Python.149150[Аллокатор объектов по умолчанию](https://python-all.ru/3.9/c-api/memory.html#default-memory-allocators) использует [аллокатор памяти pymalloc](https://python-all.ru/3.9/c-api/memory.html#pymalloc).151152> **Предупреждение**153>154> При использовании этих функций необходимо удерживать [GIL](https://python-all.ru/3.9/glossary.html#term-global-interpreter-lock).155156#### `void* PyObject_Malloc(size_t n)`157158Выделяет *n* байт и возвращает указатель типа `void*` на выделенную память или `NULL`, если запрос не удался.159160Запрос нуля байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyObject_Malloc(1)`. Память не будет инициализирована каким-либо образом.161162#### `void* PyObject_Calloc(size_t nelem, size_t elsize)`163164Выделяет *nelem* элементов, каждый размером в байтах *elsize*, и возвращает указатель типа `void*` на выделенную память или `NULL`, если запрос не удался. Память инициализируется нулями.165166Запрос нуля элементов или элементов размером ноль байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyObject_Calloc(1, 1)`.167168Новое в версии 3.5.169170#### `void* PyObject_Realloc(void *p, size_t n)`171172Изменяет размер блока памяти, на который указывает *p*, до *n* байт. Содержимое останется неизменным в пределах меньшего из старого и нового размеров.173174Если *p* равен `NULL`, вызов эквивалентен `PyObject_Malloc(n)`; в противном случае, если *n* равен нулю, размер блока памяти изменяется, но он не освобождается, и возвращаемый указатель не равен `NULL`.175176Если *p* не равен `NULL`, он должен быть возвращён предыдущим вызовом [`PyObject_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Malloc), [`PyObject_Realloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Realloc) или [`PyObject_Calloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Calloc).177178Если запрос не удался, [`PyObject_Realloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Realloc) возвращает `NULL`, а *p* остаётся корректным указателем на предыдущую область памяти.179180#### `void PyObject_Free(void *p)`181182Освобождает блок памяти, на который указывает *p*. Этот блок должен быть возвращён предыдущим вызовом [`PyObject_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Malloc), [`PyObject_Realloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Realloc) или [`PyObject_Calloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Calloc). В противном случае, или если до этого был вызван `PyObject_Free(p)`, поведение не определено.183184Если *p* равен `NULL`, то никаких действий не выполняется.185186## Аллокаторы памяти по умолчанию187188Аллокаторы памяти по умолчанию:189190| Конфигурация | Имя | PyMem\_RawMalloc | PyMem\_Malloc | PyObject\_Malloc |191| --- | --- | --- | --- | --- |192| Релизная сборка | `"pymalloc"` | `malloc` | `pymalloc` | `pymalloc` |193| Отладочная сборка | `"pymalloc_debug"` | `malloc` + отладка | `pymalloc` + отладка | `pymalloc` + отладка |194| Релизная сборка, без pymalloc | `"malloc"` | `malloc` | `malloc` | `malloc` |195| Отладочная сборка, без pymalloc | `"malloc_debug"` | `malloc` + отладка | `malloc` + отладка | `malloc` + отладка |196197Условные обозначения:198199- Имя: значение для [`PYTHONMALLOC`](https://python-all.ru/3.9/using/cmdline.html#envvar-PYTHONMALLOC) переменной окружения200- `malloc`: системные аллокаторы из стандартной библиотеки C, функции C: `malloc()`, `calloc()`, `realloc()` и `free()`201- `pymalloc`: [аллокатор памяти pymalloc](https://python-all.ru/3.9/c-api/memory.html#pymalloc)202- «+ debug»: с отладочными хуками, установленными [`PyMem_SetupDebugHooks()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_SetupDebugHooks)203204## Настройка распределителей памяти205206Новое в версии 3.4.207208**`PyMemAllocatorEx`**209210Структура, используемая для описания распределителя блоков памяти. Структура содержит следующие поля:211212| Поле | Значение |213| --- | --- |214| `void *ctx` | контекст пользователя, передаваемый первым аргументом |215| `void* malloc(void *ctx, size_t size)` | выделить блок памяти |216| `void* calloc(void *ctx, size_t nelem, size_t elsize)` | выделить блок памяти, инициализированный нулями |217| `void* realloc(void *ctx, void *ptr, size_t new_size)` | выделить или изменить размер блока памяти |218| `void free(void *ctx, void *ptr)` | освободить блок памяти |219220Изменено в версии 3.5: Структура `PyMemAllocator` была переименована в [`PyMemAllocatorEx`](https://python-all.ru/3.9/c-api/memory.html#c.PyMemAllocatorEx), и добавлено новое поле `calloc`.221222**`PyMemAllocatorDomain`**223224Перечисление, используемое для идентификации домена распределителя. Домены:225226**`PYMEM_DOMAIN_RAW`**227228Функции:229230- [`PyMem_RawMalloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawMalloc)231- [`PyMem_RawRealloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawRealloc)232- [`PyMem_RawCalloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawCalloc)233- [`PyMem_RawFree()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawFree)234235**`PYMEM_DOMAIN_MEM`**236237Функции:238239- [`PyMem_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Malloc),240- [`PyMem_Realloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Realloc)241- [`PyMem_Calloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Calloc)242- [`PyMem_Free()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Free)243244**`PYMEM_DOMAIN_OBJ`**245246Функции:247248- [`PyObject_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Malloc)249- [`PyObject_Realloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Realloc)250- [`PyObject_Calloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Calloc)251- [`PyObject_Free()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Free)252253#### `void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)`254255Получить распределитель блоков памяти для указанного домена.256257#### `void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)`258259Установить распределитель блоков памяти для указанного домена.260261Новый распределитель должен возвращать отличный от `NULL` указатель при запросе нулевого количества байт.262263Для области [`PYMEM_DOMAIN_RAW`](https://python-all.ru/3.9/c-api/memory.html#c.PYMEM_DOMAIN_RAW) распределитель должен быть потокобезопасным: [GIL](https://python-all.ru/3.9/glossary.html#term-global-interpreter-lock) не удерживается, когда вызывается распределитель.264265Если новый распределитель не является перехватчиком (не вызывает предыдущий распределитель), необходимо вызвать функцию [`PyMem_SetupDebugHooks()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_SetupDebugHooks), чтобы переустановить отладочные перехватчики поверх нового распределителя.266267#### `void PyMem_SetupDebugHooks(void)`268269Настраивает хуки для обнаружения ошибок в функциях аллокатора памяти Python.270271Недавно выделенная память заполняется байтом `0xCD` (`CLEANBYTE`), освобождённая память заполняется байтом `0xDD` (`DEADBYTE`). Блоки памяти окружены «запрещёнными байтами» (`FORBIDDENBYTE`: байт `0xFD`).272273Проверки во время выполнения:274275- Обнаруживает нарушения API, например: [`PyObject_Free()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Free) вызвана для буфера, выделенного [`PyMem_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Malloc)276- Обнаруживает запись перед началом буфера (недополнение буфера)277- Обнаруживает запись после конца буфера (переполнение буфера)278- Проверяет, что [GIL](https://python-all.ru/3.9/glossary.html#term-global-interpreter-lock) удерживается, когда вызываются функции распределителя для областей [`PYMEM_DOMAIN_OBJ`](https://python-all.ru/3.9/c-api/memory.html#c.PYMEM_DOMAIN_OBJ) (например: [`PyObject_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Malloc)) и [`PYMEM_DOMAIN_MEM`](https://python-all.ru/3.9/c-api/memory.html#c.PYMEM_DOMAIN_MEM) (например: [`PyMem_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Malloc)).279280В случае ошибки отладочные перехватчики используют модуль [`tracemalloc`](https://python-all.ru/3.9/library/tracemalloc.html#module-tracemalloc), чтобы получить трассировку того места, где был выделен блок памяти. Трассировка отображается только если [`tracemalloc`](https://python-all.ru/3.9/library/tracemalloc.html#module-tracemalloc) отслеживает выделения памяти Python и этот блок памяти отслеживался.281282Эти перехватчики [устанавливаются по умолчанию](https://python-all.ru/3.9/c-api/memory.html#default-memory-allocators), если Python скомпилирован в режиме отладки. Переменную окружения [`PYTHONMALLOC`](https://python-all.ru/3.9/using/cmdline.html#envvar-PYTHONMALLOC) можно использовать для установки отладочных перехватчиков на Python, скомпилированном в режиме выпуска.283284Изменено в версии 3.6: Теперь эта функция также работает на Python, скомпилированном в режиме выпуска. В случае ошибки отладочные перехватчики теперь используют [`tracemalloc`](https://python-all.ru/3.9/library/tracemalloc.html#module-tracemalloc) для получения трассировки того места, где был выделен блок памяти. Отладочные перехватчики теперь также проверяют, удерживается ли GIL при вызове функций областей [`PYMEM_DOMAIN_OBJ`](https://python-all.ru/3.9/c-api/memory.html#c.PYMEM_DOMAIN_OBJ) и [`PYMEM_DOMAIN_MEM`](https://python-all.ru/3.9/c-api/memory.html#c.PYMEM_DOMAIN_MEM).285286Изменено в версии 3.8: Байтовые маски `0xCB` (`CLEANBYTE`), `0xDB` (`DEADBYTE`) и `0xFB` (`FORBIDDENBYTE`) заменены на `0xCD`, `0xDD` и `0xFD`, чтобы использовать те же значения, что и отладочные `malloc()` и `free()` Windows CRT.287288## Распределитель pymalloc289290В Python имеется аллокатор *pymalloc*, оптимизированный для небольших объектов (размером не более 512 байт) с коротким временем жизни. Он использует отображения памяти, называемые «аренами», фиксированного размера 256 Кб. Для выделений более 512 байт он переключается на [`PyMem_RawMalloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawMalloc) и [`PyMem_RawRealloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_RawRealloc).291292*pymalloc* – это [распределитель по умолчанию](https://python-all.ru/3.9/c-api/memory.html#default-memory-allocators) для доменов [`PYMEM_DOMAIN_MEM`](https://python-all.ru/3.9/c-api/memory.html#c.PYMEM_DOMAIN_MEM) (например: [`PyMem_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyMem_Malloc)) и [`PYMEM_DOMAIN_OBJ`](https://python-all.ru/3.9/c-api/memory.html#c.PYMEM_DOMAIN_OBJ) (например: [`PyObject_Malloc()`](https://python-all.ru/3.9/c-api/memory.html#c.PyObject_Malloc)).293294Распределитель арен использует следующие функции:295296- `VirtualAlloc()` и `VirtualFree()` в Windows,297- `mmap()` и `munmap()`, если доступно,298- `malloc()` и `free()` в противном случае.299300### Настройка аллокатора арен pymalloc301302Новое в версии 3.4.303304**`PyObjectArenaAllocator`**305306Структура, используемая для описания аллокатора арен. Структура содержит три поля:307308| Поле | Значение |309| --- | --- |310| `void *ctx` | контекст пользователя, передаваемый первым аргументом |311| `void* alloc(void *ctx, size_t size)` | выделить арену размером bytes |312| `void free(void *ctx, void *ptr, size_t size)` | освободить арену |313314#### `void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)`315316Получить аллокатор арен.317318#### `void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)`319320Установить аллокатор арен.321322## C API tracemalloc323324Добавлено в версии 3.7.325326#### `int PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, size_t size)`327328Отследить выделенный блок памяти в модуле [`tracemalloc`](https://python-all.ru/3.9/library/tracemalloc.html#module-tracemalloc).329330Возвращает `0` в случае успеха, `-1` в случае ошибки (не удалось выделить память для хранения трассировки). Возвращает `-2`, если tracemalloc отключен.331332Если блок памяти уже отслеживается, обновить существующую трассировку.333334#### `int PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)`335336Перестать отслеживать выделенный блок памяти в модуле [`tracemalloc`](https://python-all.ru/3.9/library/tracemalloc.html#module-tracemalloc). Ничего не делать, если блок не отслеживался.337338Возвращает `-2`, если tracemalloc отключен, в противном случае возвращает `0`.339340## Примеры341342Вот пример из раздела [Обзор](https://python-all.ru/3.9/c-api/memory.html#memoryoverview), переписанный так, чтобы буфер ввода-вывода выделялся из кучи Python с помощью первого набора функций:343344```c345PyObject *res;346char *buf = (char *) PyMem_Malloc(BUFSIZ); /* для ввода-вывода */347348if (buf == NULL)349    return PyErr_NoMemory();350/* ...Выполнить некоторые операции ввода-вывода с buf... */351res = PyBytes_FromString(buf);352PyMem_Free(buf); /* выделено с помощью PyMem_Malloc */353return res;354```355356Тот же код с использованием тип-ориентированного набора функций:357358```c359PyObject *res;360char *buf = PyMem_New(char, BUFSIZ); /* для ввода-вывода */361362if (buf == NULL)363    return PyErr_NoMemory();364/* ...Выполнить некоторые операции ввода-вывода с buf... */365res = PyBytes_FromString(buf);366PyMem_Del(buf); /* выделено с помощью PyMem_New */367return res;368```369370Обратите внимание, что в двух приведённых выше примерах буфер всегда обрабатывается с помощью функций из одного и того же набора. Действительно, для данного блока памяти необходимо использовать одно и то же семейство API для работы с памятью, чтобы риск смешивания разных аллокаторов был сведён к минимуму. Следующая последовательность кода содержит две ошибки, одна из которых помечена как *фатальная*, поскольку она смешивает два разных аллокатора, работающих с разными кучами.371372```c373char *buf1 = PyMem_New(char, BUFSIZ);374char *buf2 = (char *) malloc(BUFSIZ);375char *buf3 = (char *) PyMem_Malloc(BUFSIZ);376...377PyMem_Del(buf3);  /* Неверно -- следует использовать PyMem_Free() */378free(buf2);       /* Верно -- выделено через malloc() */379free(buf1);       /* Фатальная ошибка – следует использовать PyMem_Del()  */380```381382В дополнение к функциям, предназначенным для работы с сырыми блоками памяти из кучи Python, объекты в Python выделяются и освобождаются с помощью [`PyObject_New()`](https://python-all.ru/3.9/c-api/allocation.html#c.PyObject_New), [`PyObject_NewVar()`](https://python-all.ru/3.9/c-api/allocation.html#c.PyObject_NewVar) и [`PyObject_Del()`](https://python-all.ru/3.9/c-api/allocation.html#c.PyObject_Del).383384Они будут описаны в следующей главе, посвящённой определению и реализации новых типов объектов на C.385