memory.md
1> **Источник:** https://python-all.ru/3.13/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.13/using/cmdline.html#envvar-PYTHONMALLOC) может использоваться для настройки распределителей памяти, используемых Python.38>39> Переменная окружения [`PYTHONMALLOCSTATS`](https://python-all.ru/3.13/using/cmdline.html#envvar-PYTHONMALLOCSTATS) может использоваться для вывода статистики [распределителя памяти pymalloc](https://python-all.ru/3.13/c-api/memory.html#pymalloc) каждый раз при создании новой арены объектов pymalloc, а также при завершении работы.4041## Домены распределителей4243Все функции выделения памяти относятся к одному из трёх различных «доменов» (см. также [`PyMemAllocatorDomain`](https://python-all.ru/3.13/c-api/memory.html#c.PyMemAllocatorDomain)). Эти домены представляют разные стратегии выделения и оптимизированы для разных целей. Конкретные детали того, как каждый домен выделяет память или какие внутренние функции вызывает, считаются деталью реализации, но для целей отладки упрощённая таблица доступна в разделе [Распределители памяти по умолчанию](https://python-all.ru/3.13/c-api/memory.html#default-memory-allocators). API, используемые для выделения и освобождения блока памяти, должны принадлежать одному домену. Например, [`PyMem_Free()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Free) должен использоваться для освобождения памяти, выделенной с помощью [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc).4445Три домена выделения:4647- Raw domain: предназначена для выделения памяти для буферов общего назначения, когда выделение *должно* производиться системным аллокатором или когда аллокатор может работать без удержания [GIL](https://python-all.ru/3.13/glossary.html#term-GIL). Память запрашивается напрямую у системы. См. [Интерфейс необработанной памяти](https://python-all.ru/3.13/c-api/memory.html#raw-memoryinterface).48- Область «Mem»: предназначена для выделения памяти для буферов Python и буферов общего назначения, когда выделение должно выполняться при удержании [GIL](https://python-all.ru/3.13/glossary.html#term-GIL). Память берётся из частной кучи Python. См. [Интерфейс памяти](https://python-all.ru/3.13/c-api/memory.html#memoryinterface).49- Объектный домен: предназначен для выделения памяти для объектов Python. Память берётся из приватной кучи Python. См. [Распределители объектов](https://python-all.ru/3.13/c-api/memory.html#objectinterface).5051> **Примечание**52>53> [Сборка со свободной многопоточностью](https://python-all.ru/3.13/glossary.html#term-free-threading) требует, чтобы только объекты Python выделялись с использованием домена «object», и чтобы все объекты Python выделялись с использованием этого домена. Это отличается от предыдущих версий Python, где это было лишь рекомендацией, а не строгим требованием.54>55> Например, буферы (не объекты Python) должны выделяться с помощью [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc), [`PyMem_RawMalloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawMalloc) или `malloc()`, но не [`PyObject_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Malloc).56>57> См. [API выделения памяти](https://python-all.ru/3.13/howto/free-threading-extensions.html#free-threaded-memory-allocation).5859## Сырой интерфейс памяти6061Следующие наборы функций являются обёртками вокруг системного аллокатора. Эти функции потокобезопасны, удерживать [GIL](https://python-all.ru/3.13/glossary.html#term-global-interpreter-lock) не требуется.6263[Стандартный сырой распределитель памяти](https://python-all.ru/3.13/c-api/memory.html#default-memory-allocators) использует следующие функции: `malloc()`, `calloc()`, `realloc()` и `free()`; вызывайте `malloc(1)` (или `calloc(1, 1)`) при запросе нулевого количества байтов.6465Добавлено в версии 3.4.6667#### `void *PyMem_RawMalloc(size_t n)`6869*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable), начиная с версии 3.13.*7071Выделяет *n* байт и возвращает указатель типа void\* на выделенную память или `NULL`, если запрос не удался.7273Запрос нуля байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyMem_RawMalloc(1)`. Память не будет инициализирована каким-либо образом.7475#### `void *PyMem_RawCalloc(size_t nelem, size_t elsize)`7677*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable), начиная с версии 3.13.*7879Выделяет *nelem* элементов размером *elsize* байт каждый и возвращает указатель типа void\* на выделенную память или `NULL`, если запрос не удался. Память инициализируется нулями.8081Запрос нулевого количества элементов или элементов размером ноль байтов возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо него был вызван `PyMem_RawCalloc(1, 1)`.8283Добавлено в версии 3.5.8485#### `void *PyMem_RawRealloc(void *p, size_t n)`8687*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable), начиная с версии 3.13.*8889Изменяет размер блока памяти, на который указывает *p*, до *n* байт. Содержимое останется неизменным в объеме, равном минимальному из старого и нового размеров.9091Если *p* равен `NULL`, вызов эквивалентен `PyMem_RawMalloc(n)`; иначе если *n* равен нулю, блок памяти изменяет размер, но не освобождается, и возвращаемый указатель отличен от `NULL`.9293Если *p* не равен `NULL`, он должен быть возвращен предыдущим вызовом [`PyMem_RawMalloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawMalloc), [`PyMem_RawRealloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawRealloc) или [`PyMem_RawCalloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawCalloc).9495В случае ошибки [`PyMem_RawRealloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawRealloc) возвращает `NULL`, и *p* остается действующим указателем на предыдущую область памяти.9697#### `void PyMem_RawFree(void *p)`9899*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable), начиная с версии 3.13.*100101Освобождает блок памяти, на который указывает *p*. Этот указатель должен быть возвращен предыдущим вызовом [`PyMem_RawMalloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawMalloc), [`PyMem_RawRealloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawRealloc) или [`PyMem_RawCalloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawCalloc). В противном случае, или если `PyMem_RawFree(p)` уже вызывался, поведение не определено.102103Если *p* равен `NULL`, то никаких действий не выполняется.104105## Интерфейс памяти106107Следующие наборы функций, основанные на стандарте ANSI C, но определяющие поведение при запросе нуля байт, доступны для выделения и освобождения памяти из кучи Python.108109[Аллокатор памяти по умолчанию](https://python-all.ru/3.13/c-api/memory.html#default-memory-allocators) использует [аллокатор памяти pymalloc](https://python-all.ru/3.13/c-api/memory.html#pymalloc).110111> **Предупреждение**112>113> При использовании этих функций необходимо удерживать [GIL](https://python-all.ru/3.13/glossary.html#term-global-interpreter-lock).114115Изменено в версии 3.6: Аллокатором по умолчанию теперь является pymalloc вместо системного `malloc()`.116117#### `void *PyMem_Malloc(size_t n)`118119*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*120121Выделяет *n* байт и возвращает указатель типа void\* на выделенную память или `NULL`, если запрос не удался.122123Запрос нуля байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyMem_Malloc(1)`. Память не будет инициализирована каким-либо образом.124125#### `void *PyMem_Calloc(size_t nelem, size_t elsize)`126127*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable) начиная с версии 3.7.*128129Выделяет *nelem* элементов размером *elsize* байт каждый и возвращает указатель типа void\* на выделенную память или `NULL`, если запрос не удался. Память инициализируется нулями.130131Запрос нуля элементов или элементов размером ноль байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyMem_Calloc(1, 1)`.132133Добавлено в версии 3.5.134135#### `void *PyMem_Realloc(void *p, size_t n)`136137*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*138139Изменяет размер блока памяти, на который указывает *p*, до *n* байт. Содержимое останется неизменным в пределах меньшего из старого и нового размеров.140141Если *p* равен `NULL`, вызов эквивалентен `PyMem_Malloc(n)`; в противном случае, если *n* равен нулю, размер блока памяти изменяется, но он не освобождается, и возвращаемый указатель не равен `NULL`.142143Если *p* не равен `NULL`, он должен быть возвращён предыдущим вызовом [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc), [`PyMem_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Realloc) или [`PyMem_Calloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Calloc).144145Если запрос не удался, [`PyMem_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Realloc) возвращает `NULL`, а *p* остаётся корректным указателем на предыдущую область памяти.146147#### `void PyMem_Free(void *p)`148149*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*150151Освобождает блок памяти, на который указывает *p*. Этот блок должен быть возвращён предыдущим вызовом [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc), [`PyMem_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Realloc) или [`PyMem_Calloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Calloc). В противном случае, или если до этого был вызван `PyMem_Free(p)`, поведение не определено.152153Если *p* равен `NULL`, то никаких действий не выполняется.154155Для удобства предоставлены следующие макросы, ориентированные на типы. Обратите внимание, что *TYPE* относится к любому типу C.156157#### `PyMem_New(TYPE, n)`158159То же, что и [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc), но выделяет `(n * sizeof(TYPE))` байт памяти. Возвращает указатель, приведенный к `TYPE*`. Память не будет инициализирована каким-либо образом.160161#### `PyMem_Resize(p, TYPE, n)`162163То же, что [`PyMem_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Realloc), но блок памяти изменяется до `(n * sizeof(TYPE))` байт. Возвращает указатель, приведённый к `TYPE*`. При возврате *p* будет указателем на новую область памяти или `NULL` в случае ошибки.164165Это макрос препроцессора C; *p* всегда переназначается. Сохраняйте исходное значение *p*, чтобы не потерять память при обработке ошибок.166167#### `void PyMem_Del(void *p)`168169То же, что и [`PyMem_Free()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Free).170171### Устаревшие псевдонимы172173Это [мягко устаревшие](https://python-all.ru/3.13/glossary.html#term-soft-deprecated) псевдонимы существующих функций и макросов. Они существуют исключительно для обратной совместимости.174175| Устаревший псевдоним | Соответствующая функция или макрос |176| --- | --- |177| PyMem\_MALLOC(size) | [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc) |178| PyMem\_NEW(type, size) | [`PyMem_New`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_New) |179| PyMem\_REALLOC(ptr, size) | [`PyMem_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Realloc) |180| PyMem\_RESIZE(ptr, type, size) | [`PyMem_Resize`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Resize) |181| PyMem\_FREE(ptr) | [`PyMem_Free()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Free) |182| PyMem\_DEL(ptr) | [`PyMem_Free()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Free) |183184Изменено в версии 3.4: Макросы теперь являются псевдонимами соответствующих функций и макросов. Ранее их поведение было тем же, но их использование не обязательно сохраняло двоичную совместимость между версиями Python.185186Устарело с версии 2.0.187188## Аллокаторы объектов189190Следующие наборы функций, основанные на стандарте ANSI C, но определяющие поведение при запросе нуля байт, доступны для выделения и освобождения памяти из кучи Python.191192> **Примечание**193>194> Нет гарантии, что память, возвращаемая этими аллокаторами, может быть успешно приведена к объекту Python при перехвате функций выделения в этой области методами, описанными в разделе [Customize Memory Allocators](https://python-all.ru/3.13/c-api/memory.html#customize-memory-allocators).195196[Аллокатор объектов по умолчанию](https://python-all.ru/3.13/c-api/memory.html#default-memory-allocators) использует [аллокатор памяти pymalloc](https://python-all.ru/3.13/c-api/memory.html#pymalloc).197198> **Предупреждение**199>200> При использовании этих функций необходимо удерживать [GIL](https://python-all.ru/3.13/glossary.html#term-global-interpreter-lock).201202#### `void *PyObject_Malloc(size_t n)`203204*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*205206Выделяет *n* байт и возвращает указатель типа void\* на выделенную память или `NULL`, если запрос не удался.207208Запрос нуля байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyObject_Malloc(1)`. Память не будет инициализирована каким-либо образом.209210#### `void *PyObject_Calloc(size_t nelem, size_t elsize)`211212*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable) начиная с версии 3.7.*213214Выделяет *nelem* элементов размером *elsize* байт каждый и возвращает указатель типа void\* на выделенную память или `NULL`, если запрос не удался. Память инициализируется нулями.215216Запрос нуля элементов или элементов размером ноль байт возвращает отличный от `NULL` указатель, если это возможно, как если бы вместо этого была вызвана `PyObject_Calloc(1, 1)`.217218Добавлено в версии 3.5.219220#### `void *PyObject_Realloc(void *p, size_t n)`221222*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*223224Изменяет размер блока памяти, на который указывает *p*, до *n* байт. Содержимое останется неизменным в пределах меньшего из старого и нового размеров.225226Если *p* равен `NULL`, вызов эквивалентен `PyObject_Malloc(n)`; в противном случае, если *n* равен нулю, размер блока памяти изменяется, но он не освобождается, и возвращаемый указатель не равен `NULL`.227228Если *p* не равен `NULL`, он должен быть возвращён предыдущим вызовом [`PyObject_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Malloc), [`PyObject_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Realloc) или [`PyObject_Calloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Calloc).229230Если запрос не удался, [`PyObject_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Realloc) возвращает `NULL`, а *p* остаётся корректным указателем на предыдущую область памяти.231232#### `void PyObject_Free(void *p)`233234*Часть [Stable ABI](https://python-all.ru/3.13/c-api/stable.html#stable).*235236Освобождает блок памяти, на который указывает *p*. Этот блок должен быть возвращён предыдущим вызовом [`PyObject_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Malloc), [`PyObject_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Realloc) или [`PyObject_Calloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Calloc). В противном случае, или если до этого был вызван `PyObject_Free(p)`, поведение не определено.237238Если *p* равен `NULL`, то никаких действий не выполняется.239240## Аллокаторы памяти по умолчанию241242Аллокаторы памяти по умолчанию:243244| Конфигурация | Имя | PyMem\_RawMalloc | PyMem\_Malloc | PyObject\_Malloc |245| --- | --- | --- | --- | --- |246| Релизная сборка | `"pymalloc"` | `malloc` | `pymalloc` | `pymalloc` |247| Отладочная сборка | `"pymalloc_debug"` | `malloc` + отладка | `pymalloc` + отладка | `pymalloc` + отладка |248| Релизная сборка, без pymalloc | `"malloc"` | `malloc` | `malloc` | `malloc` |249| Отладочная сборка, без pymalloc | `"malloc_debug"` | `malloc` + отладка | `malloc` + отладка | `malloc` + отладка |250251Условные обозначения:252253- Имя: значение для переменной окружения [`PYTHONMALLOC`](https://python-all.ru/3.13/using/cmdline.html#envvar-PYTHONMALLOC).254- `malloc`: системные аллокаторы из стандартной библиотеки C, функции языка C: `malloc()`, `calloc()`, `realloc()` и `free()`.255- `pymalloc`: [аллокатор памяти pymalloc](https://python-all.ru/3.13/c-api/memory.html#pymalloc).256- `mimalloc`: [распределитель памяти mimalloc](https://python-all.ru/3.13/c-api/memory.html#mimalloc). Если поддержка mimalloc недоступна, будет использоваться распределитель pymalloc.257- «+ отладка»: с [отладочными перехватчиками на аллокаторах памяти Python](https://python-all.ru/3.13/c-api/memory.html#pymem-debug-hooks).258- “Debug build”: [сборка Python в режиме отладки](https://python-all.ru/3.13/using/configure.html#debug-build).259260## Настройка распределителей памяти261262Добавлено в версии 3.4.263264#### `type PyMemAllocatorEx`265266Структура, используемая для описания распределителя блоков памяти. Структура содержит следующие поля:267268| Поле | Значение |269| --- | --- |270| `void *ctx` | контекст пользователя, передаваемый первым аргументом |271| `void* malloc(void *ctx, size_t size)` | выделить блок памяти |272| `void* calloc(void *ctx, size_t nelem, size_t elsize)` | выделить блок памяти, инициализированный нулями |273| `void* realloc(void *ctx, void *ptr, size_t new_size)` | выделить или изменить размер блока памяти |274| `void free(void *ctx, void *ptr)` | освободить блок памяти |275276Изменено в версии 3.5: Структура `PyMemAllocator` была переименована в [`PyMemAllocatorEx`](https://python-all.ru/3.13/c-api/memory.html#c.PyMemAllocatorEx), и добавлено новое поле `calloc`.277278#### `type PyMemAllocatorDomain`279280Перечисление, используемое для идентификации домена распределителя. Домены:281282#### `PYMEM_DOMAIN_RAW`283284Функции:285286- [`PyMem_RawMalloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawMalloc)287- [`PyMem_RawRealloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawRealloc)288- [`PyMem_RawCalloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawCalloc)289- [`PyMem_RawFree()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawFree)290291#### `PYMEM_DOMAIN_MEM`292293Функции:294295- [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc),296- [`PyMem_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Realloc)297- [`PyMem_Calloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Calloc)298- [`PyMem_Free()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Free)299300#### `PYMEM_DOMAIN_OBJ`301302Функции:303304- [`PyObject_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Malloc)305- [`PyObject_Realloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Realloc)306- [`PyObject_Calloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Calloc)307- [`PyObject_Free()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Free)308309#### `void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)`310311Получить распределитель блоков памяти для указанного домена.312313#### `void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)`314315Установить распределитель блоков памяти для указанного домена.316317Новый распределитель должен возвращать отличный от `NULL` указатель при запросе нулевого количества байт.318319Для области [`PYMEM_DOMAIN_RAW`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_RAW) распределитель должен быть потокобезопасным: [GIL](https://python-all.ru/3.13/glossary.html#term-global-interpreter-lock) не удерживается, когда вызывается распределитель.320321Для остальных областей распределитель также должен быть потокобезопасным: распределитель может вызываться в разных интерпретаторах, которые не используют общий `GIL`.322323Если новый распределитель не является перехватчиком (не вызывает предыдущий распределитель), необходимо вызвать функцию [`PyMem_SetupDebugHooks()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_SetupDebugHooks), чтобы переустановить отладочные перехватчики поверх нового распределителя.324325См. также [`PyPreConfig.allocator`](https://python-all.ru/3.13/c-api/init_config.html#c.PyPreConfig.allocator) и [предварительную инициализацию Python с помощью PyPreConfig](https://python-all.ru/3.13/c-api/init_config.html#c-preinit).326327> **Предупреждение**328>329> [`PyMem_SetAllocator()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_SetAllocator) имеет следующее контрактное соглашение:330>331> - Его можно вызывать после [`Py_PreInitialize()`](https://python-all.ru/3.13/c-api/init_config.html#c.Py_PreInitialize) и до [`Py_InitializeFromConfig()`](https://python-all.ru/3.13/c-api/init.html#c.Py_InitializeFromConfig) для установки пользовательского распределителя памяти. На установленный распределитель не накладывается никаких ограничений, кроме тех, что накладываются областью (например, Raw Domain позволяет вызывать распределитель без удержания GIL). См. [раздел об областях распределителя](https://python-all.ru/3.13/c-api/memory.html#id1) для получения дополнительной информации.332> - Если вызывается после завершения инициализации Python (после вызова [`Py_InitializeFromConfig()`](https://python-all.ru/3.13/c-api/init.html#c.Py_InitializeFromConfig)), распределитель **должен** оборачивать существующий распределитель. Замена текущего распределителя на произвольный другой **не поддерживается**.333334Изменено в версии 3.12: Все распределители должны быть потокобезопасными.335336#### `void PyMem_SetupDebugHooks(void)`337338Устанавливает [отладочные ловушки в распределителях памяти Python](https://python-all.ru/3.13/c-api/memory.html#pymem-debug-hooks) для обнаружения ошибок памяти.339340## Отладочные ловушки в распределителях памяти Python341342Когда [Python собран в режиме отладки](https://python-all.ru/3.13/using/configure.html#debug-build), функция [`PyMem_SetupDebugHooks()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_SetupDebugHooks) вызывается во время [преинициализации Python](https://python-all.ru/3.13/c-api/init_config.html#c-preinit) для установки отладочных ловушек в распределителях памяти Python для обнаружения ошибок памяти.343344Переменная окружения [`PYTHONMALLOC`](https://python-all.ru/3.13/using/cmdline.html#envvar-PYTHONMALLOC) может использоваться для установки отладочных ловушек в Python, скомпилированном в релизном режиме (например: `PYTHONMALLOC=debug`).345346Функция [`PyMem_SetupDebugHooks()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_SetupDebugHooks) может использоваться для установки отладочных ловушек после вызова [`PyMem_SetAllocator()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_SetAllocator).347348Эти отладочные ловушки заполняют динамически выделенные блоки памяти специальными, распознаваемыми битовыми шаблонами. Вновь выделенная память заполняется байтом `0xCD` (`PYMEM_CLEANBYTE`), освобождённая память – байтом `0xDD` (`PYMEM_DEADBYTE`). Блоки памяти окружены «запрещёнными байтами», заполненными байтом `0xFD` (`PYMEM_FORBIDDENBYTE`). Строки из этих байтов вряд ли являются допустимыми адресами, числами с плавающей точкой или строками ASCII.349350Проверки во время выполнения:351352- Обнаруживает нарушения API. Например, определяет, была ли [`PyObject_Free()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Free) вызвана для блока памяти, выделенного функцией [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc).353- Обнаруживает запись перед началом буфера (недополнение буфера).354- Обнаруживает запись после конца буфера (переполнение буфера).355- Проверяет, что [GIL](https://python-all.ru/3.13/glossary.html#term-global-interpreter-lock) удерживается при вызове функций распределителя областей [`PYMEM_DOMAIN_OBJ`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_OBJ) (например: [`PyObject_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Malloc)) и [`PYMEM_DOMAIN_MEM`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_MEM) (например: [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc)).356357При ошибке отладочные ловушки используют модуль [`tracemalloc`](https://python-all.ru/3.13/library/tracemalloc.html#module-tracemalloc) для получения traceback'а места, где был выделен блок памяти. Traceback отображается только в том случае, если `tracemalloc` отслеживает выделения памяти Python, и блок памяти был отслежен.358359Пусть *S* = `sizeof(size_t)`. `2*S` байтов добавляется с каждого конца каждого блока из *N* запрошенных байтов. Расположение в памяти выглядит следующим образом, где p представляет адрес, возвращаемый функцией типа malloc или realloc (`p[i:j]` означает срез байтов от `*(p+i)` включительно до `*(p+j)` исключительно; обратите внимание, что обработка отрицательных индексов отличается от среза Python):360361**`p[-2*S:-S]`**362363Количество байтов, первоначально запрошенное. Это size\_t с прямым порядком байтов (легче читать в дампе памяти).364365**`p[-S]`**366367Идентификатор API (символ ASCII):368369- `'r'` для [`PYMEM_DOMAIN_RAW`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_RAW).370- `'m'` для [`PYMEM_DOMAIN_MEM`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_MEM).371- `'o'` для [`PYMEM_DOMAIN_OBJ`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_OBJ).372373**`p[-S+1:0]`**374375Копии PYMEM\_FORBIDDENBYTE. Используются для обнаружения записи и чтения до начала буфера.376377**`p[0:N]`**378379Запрошенная память, заполненная копиями PYMEM\_CLEANBYTE, используется для обнаружения ссылок на неинициализированную память. При вызове функции типа realloc с запросом большего блока памяти новые избыточные байты также заполняются PYMEM\_CLEANBYTE. При вызове функции типа free эти байты перезаписываются PYMEM\_DEADBYTE для обнаружения ссылок на освобождённую память. При вызове функции типа realloc с запросом меньшего блока памяти избыточные старые байты также заполняются PYMEM\_DEADBYTE.380381**`p[N:N+S]`**382383Копии PYMEM\_FORBIDDENBYTE. Используются для обнаружения записи и чтения после конца буфера.384385**`p[N+S:N+2*S]`**386387Используется только если определён макрос `PYMEM_DEBUG_SERIALNO` (по умолчанию не определён).388389Серийный номер, увеличиваемый на 1 при каждом вызове функции типа malloc или realloc. Big-endian `size_t`. Если позже будет обнаружена «плохая память», серийный номер даёт отличный способ установить точку останова при следующем запуске, чтобы зафиксировать момент, когда этот блок был выдан. Статическая функция bumpserialno() в obmalloc.c – единственное место, где серийный номер увеличивается, и она существует, чтобы можно было легко установить такую точку останова.390391Функция типа realloc или free сначала проверяет, что байты PYMEM\_FORBIDDENBYTE на каждом конце не повреждены. Если они были изменены, диагностический вывод записывается в stderr, и программа аварийно завершается через Py\_FatalError(). Другой основной режим отказа – провоцирование ошибки памяти, когда программа читает один из специальных битовых шаблонов и пытается использовать его как адрес. Если затем войти в отладчик и посмотреть на объект, скорее всего, можно увидеть, что он полностью заполнен PYMEM\_DEADBYTE (что означает использование освобождённой памяти) или PYMEM\_CLEANBYTE (что означает использование неинициализированной памяти).392393Изменено в версии 3.6: Функция [`PyMem_SetupDebugHooks()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_SetupDebugHooks) теперь также работает в Python, скомпилированном в режиме выпуска. При ошибке отладочные перехватчики теперь используют [`tracemalloc`](https://python-all.ru/3.13/library/tracemalloc.html#module-tracemalloc) для получения трассировки, где был выделен блок памяти. Отладочные перехватчики теперь также проверяют, удерживается ли GIL при вызове функций областей [`PYMEM_DOMAIN_OBJ`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_OBJ) и [`PYMEM_DOMAIN_MEM`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_MEM).394395Изменено в версии 3.8: Байтовые шаблоны `0xCB` (`PYMEM_CLEANBYTE`), `0xDB` (`PYMEM_DEADBYTE`) и `0xFB` (`PYMEM_FORBIDDENBYTE`) были заменены на `0xCD`, `0xDD` и `0xFD`, чтобы использовать те же значения, что и отладочные `malloc()` и `free()` CRT Windows.396397## Распределитель pymalloc398399В Python есть распределитель *pymalloc*, оптимизированный для небольших объектов (размером до 512 байт включительно) с коротким временем жизни. Он использует отображения памяти, называемые «аренами», фиксированного размера: 256 Кбайт на 32-разрядных платформах или 1 Мбайт на 64-разрядных платформах. Для выделений памяти размером более 512 байт он обращается к [`PyMem_RawMalloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawMalloc) и [`PyMem_RawRealloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_RawRealloc).400401*pymalloc* – это [распределитель по умолчанию](https://python-all.ru/3.13/c-api/memory.html#default-memory-allocators) для доменов [`PYMEM_DOMAIN_MEM`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_MEM) (например: [`PyMem_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyMem_Malloc)) и [`PYMEM_DOMAIN_OBJ`](https://python-all.ru/3.13/c-api/memory.html#c.PYMEM_DOMAIN_OBJ) (например: [`PyObject_Malloc()`](https://python-all.ru/3.13/c-api/memory.html#c.PyObject_Malloc)).402403Распределитель арен использует следующие функции:404405- `VirtualAlloc()` и `VirtualFree()` в Windows,406- `mmap()` и `munmap()`, если доступно,407- `malloc()` и `free()` в противном случае.408409Этот аллокатор отключается, если Python собран с опцией [`--without-pymalloc`](https://python-all.ru/3.13/using/configure.html#cmdoption-without-pymalloc). Его также можно отключить во время выполнения с помощью переменной окружения [`PYTHONMALLOC`](https://python-all.ru/3.13/using/cmdline.html#envvar-PYTHONMALLOC) (например, `PYTHONMALLOC=malloc`).410411Обычно имеет смысл отключать аллокатор pymalloc при сборке Python с AddressSanitizer ([`--with-address-sanitizer`](https://python-all.ru/3.13/using/configure.html#cmdoption-with-address-sanitizer)), который помогает выявлять низкоуровневые ошибки в C-коде.412413### Настройка аллокатора арен pymalloc414415Добавлено в версии 3.4.416417#### `type PyObjectArenaAllocator`418419Структура, используемая для описания аллокатора арен. Структура содержит три поля:420421| Поле | Значение |422| --- | --- |423| `void *ctx` | контекст пользователя, передаваемый первым аргументом |424| `void* alloc(void *ctx, size_t size)` | выделить арену размером bytes |425| `void free(void *ctx, void *ptr, size_t size)` | освободить арену |426427#### `void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)`428429Получить аллокатор арен.430431#### `void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)`432433Установить аллокатор арен.434435## Аллокатор mimalloc436437Добавлено в версии 3.13.438439Python поддерживает распределитель mimalloc при наличии поддержки на соответствующей платформе. mimalloc – «универсальный распределитель с отличными характеристиками производительности. Изначально разработан Дааном Лейеном для систем времени выполнения языков Koka и Lean».440441## C API tracemalloc442443Добавлено в версии 3.7.444445#### `int PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, size_t size)`446447Отследить выделенный блок памяти в модуле [`tracemalloc`](https://python-all.ru/3.13/library/tracemalloc.html#module-tracemalloc).448449Возвращает `0` в случае успеха, `-1` в случае ошибки (не удалось выделить память для хранения трассировки). Возвращает `-2`, если tracemalloc отключен.450451Если блок памяти уже отслеживается, обновить существующую трассировку.452453#### `int PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)`454455Перестать отслеживать выделенный блок памяти в модуле [`tracemalloc`](https://python-all.ru/3.13/library/tracemalloc.html#module-tracemalloc). Ничего не делать, если блок не отслеживался.456457Возвращает `-2`, если tracemalloc отключен, в противном случае возвращает `0`.458459## Примеры460461Вот пример из раздела [Обзор](https://python-all.ru/3.13/c-api/memory.html#memoryoverview), переписанный так, чтобы буфер ввода-вывода выделялся из кучи Python с помощью первого набора функций:462463```c464PyObject *res;465char *buf = (char *) PyMem_Malloc(BUFSIZ); /* для ввода-вывода */466467if (buf == NULL)468 return PyErr_NoMemory();469/* ...Выполнить некоторые операции ввода-вывода с buf... */470res = PyBytes_FromString(buf);471PyMem_Free(buf); /* выделено с помощью PyMem_Malloc */472return res;473```474475Тот же код с использованием тип-ориентированного набора функций:476477```c478PyObject *res;479char *buf = PyMem_New(char, BUFSIZ); /* для ввода-вывода */480481if (buf == NULL)482 return PyErr_NoMemory();483/* ...Выполнить некоторые операции ввода-вывода с buf... */484res = PyBytes_FromString(buf);485PyMem_Del(buf); /* выделено с помощью PyMem_New */486return res;487```488489Обратите внимание, что в двух приведённых выше примерах буфер всегда обрабатывается с помощью функций из одного и того же набора. Действительно, для данного блока памяти необходимо использовать одно и то же семейство API для работы с памятью, чтобы риск смешивания разных аллокаторов был сведён к минимуму. Следующая последовательность кода содержит две ошибки, одна из которых помечена как *фатальная*, поскольку она смешивает два разных аллокатора, работающих с разными кучами.490491```c492char *buf1 = PyMem_New(char, BUFSIZ);493char *buf2 = (char *) malloc(BUFSIZ);494char *buf3 = (char *) PyMem_Malloc(BUFSIZ);495...496PyMem_Del(buf3); /* Неверно -- следует использовать PyMem_Free() */497free(buf2); /* Верно -- выделено через malloc() */498free(buf1); /* Фатальная ошибка – следует использовать PyMem_Del() */499```500501В дополнение к функциям, предназначенным для работы с сырыми блоками памяти из кучи Python, объекты в Python выделяются и освобождаются с помощью [`PyObject_New`](https://python-all.ru/3.13/c-api/allocation.html#c.PyObject_New), [`PyObject_NewVar`](https://python-all.ru/3.13/c-api/allocation.html#c.PyObject_NewVar) и [`PyObject_Del()`](https://python-all.ru/3.13/c-api/allocation.html#c.PyObject_Del).502503Они будут описаны в следующей главе, посвящённой определению и реализации новых типов объектов на C.504