Содержание страницы
Управление памятью¶Memory Management
Обзор¶Overview
Управление памятью в Python включает приватную кучу, содержащую все объекты и структуры данных Python. Управление этой приватной кучей внутренне обеспечивается менеджером памяти Python. Менеджер памяти Python имеет различные компоненты, которые занимаются разными аспектами управления динамической памятью, такими как совместное использование, сегментация, предварительное выделение или кеширование.
На нижнем уровне сырой распределитель памяти гарантирует, что в приватной куче достаточно места для хранения всех данных Python, взаимодействуя с менеджером памяти операционной системы. Поверх сырого распределителя памяти несколько объектно-специфичных распределителей работают с той же кучей и реализуют различные политики управления памятью, адаптированные к особенностям каждого типа объектов. Например, целочисленные объекты управляются в куче иначе, чем строки, кортежи или словари, поскольку целые числа подразумевают другие требования к хранению и компромиссы между скоростью и объёмом. Таким образом, менеджер памяти Python делегирует часть работы объектно-специфичным распределителям, но следит, чтобы последние работали в границах приватной кучи.
Важно понимать, что управление кучей Python выполняется самим интерпретатором, и пользователь не может на него повлиять, даже если регулярно манипулирует указателями на объекты в этой куче. Выделение памяти в куче для объектов Python и других внутренних буферов выполняется по требованию менеджером памяти Python через функции Python/C API, перечисленные в этом документе.
Чтобы избежать повреждения памяти, разработчики расширений никогда не должны пытаться работать с объектами Python с помощью функций, экспортируемых библиотекой C: malloc(), calloc(), realloc() и free(). Это приведёт к смешанным вызовам между распределителем C и менеджером памяти Python с фатальными последствиями, поскольку они реализуют разные алгоритмы и работают с разными кучами. Однако можно безопасно выделять и освобождать блоки памяти с помощью распределителя библиотеки C для отдельных целей, как показано в следующем примере:
PyObject *res;
char *buf = (char *) malloc(BUFSIZ); /* для ввода-вывода */
if (buf == NULL)
return PyErr_NoMemory();
...Do some I/O operation involving buf...
res = PyBytes_FromString(buf);
free(buf); /* выделено через malloc */
return res;
В этом примере запрос памяти для буфера ввода-вывода обрабатывается распределителем библиотеки C. Менеджер памяти Python участвует только в выделении объекта bytes, возвращаемого в результате.
Однако в большинстве ситуаций рекомендуется выделять память именно из кучи Python, поскольку она находится под контролем менеджера памяти Python. Например, это необходимо, когда интерпретатор расширяется новыми типами объектов, написанными на C. Ещё одна причина использования кучи Python – желание информировать менеджер памяти Python о потребностях в памяти модуля расширения. Даже если запрашиваемая память используется исключительно для внутренних, узкоспециализированных целей, делегирование всех запросов памяти менеджеру памяти Python позволяет интерпретатору получить более точную картину общего объёма используемой памяти. Следовательно, при определённых обстоятельствах менеджер памяти Python может запускать или не запускать соответствующие действия, такие как сборка мусора, уплотнение памяти или другие профилактические процедуры. Обратите внимание, что при использовании распределителя библиотеки C, как показано в предыдущем примере, выделенная память для буфера ввода-вывода полностью выпадает из-под контроля менеджера памяти Python.
См. также
Переменная окружения PYTHONMALLOC может использоваться для настройки распределителей памяти, используемых Python.
Переменная окружения PYTHONMALLOCSTATS может использоваться для вывода статистики распределителя памяти pymalloc каждый раз при создании новой арены объектов pymalloc, а также при завершении работы.
Домены распределителей¶Allocator Domains
Все функции выделения памяти относятся к одному из трёх различных «доменов» (см. также PyMemAllocatorDomain). Эти домены представляют разные стратегии выделения и оптимизированы для разных целей. Конкретные детали того, как каждый домен выделяет память или какие внутренние функции вызывает, считаются деталью реализации, но для целей отладки упрощённая таблица доступна в разделе Распределители памяти по умолчанию. API, используемые для выделения и освобождения блока памяти, должны принадлежать одному домену. Например, PyMem_Free() должен использоваться для освобождения памяти, выделенной с помощью PyMem_Malloc().
Три домена выделения:
Сырой домен: предназначен для выделения памяти для буферов общего назначения, когда выделение должно осуществляться системным распределителем или когда распределитель может работать без присоединённого состояния потока. Память запрашивается напрямую у системы. См. Сырой интерфейс памяти.
Домен «Mem»: предназначен для выделения памяти для буферов Python и буферов общего назначения, когда выделение должно выполняться с присоединённым состоянием потока. Память берётся из приватной кучи Python. См. Интерфейс памяти.
Объектный домен: предназначен для выделения памяти для объектов Python. Память берётся из приватной кучи Python. См. Распределители объектов.
Примечание
Сборка со свободной многопоточностью требует, чтобы только объекты Python выделялись с использованием домена «object», и чтобы все объекты Python выделялись с использованием этого домена. Это отличается от предыдущих версий Python, где это было лишь рекомендацией, а не строгим требованием.
Например, буферы (не объекты Python) должны выделяться с помощью PyMem_Malloc(), PyMem_RawMalloc() или malloc(), но не PyObject_Malloc().
См. API выделения памяти.
Сырой интерфейс памяти¶Raw Memory Interface
Следующие наборы функций являются обёртками над системным распределителем. Эти функции потокобезопасны, поэтому состояние потока не должно быть присоединено.
Стандартный сырой распределитель памяти использует следующие функции: malloc(), calloc(), realloc() и free(); вызывайте malloc(1) (или calloc(1, 1)) при запросе нулевого количества байтов.
Добавлено в версии 3.4.
-
void *PyMem_RawMalloc(size_t n)¶
- Часть Stable ABI, начиная с версии 3.13.
Выделяет n байтов и возвращает указатель типа void* на выделенную память, или
NULL, если запрос завершился неудачей.Запрос нулевого количества байтов возвращает отличный от
NULLуказатель, если это возможно, как если бы вместо него был вызванPyMem_RawMalloc(1). Память не будет инициализирована каким-либо образом.
-
void *PyMem_RawCalloc(size_t nelem, size_t elsize)¶
- Часть Stable ABI, начиная с версии 3.13.
Выделяет nelem элементов, каждый размером elsize байтов, и возвращает указатель типа void* на выделенную память, или
NULL, если запрос завершился неудачей. Память инициализируется нулями.Запрос нулевого количества элементов или элементов размером ноль байтов возвращает отличный от
NULLуказатель, если это возможно, как если бы вместо него был вызванPyMem_RawCalloc(1, 1).Добавлено в версии 3.5.
-
void *PyMem_RawRealloc(void *p, size_t n)¶
- Часть Stable ABI, начиная с версии 3.13.
Изменяет размер блока памяти, на который указывает p, до n байт. Содержимое останется неизменным в объеме, равном минимальному из старого и нового размеров.
Если p равен
NULL, вызов эквивалентенPyMem_RawMalloc(n); иначе если n равен нулю, блок памяти изменяет размер, но не освобождается, и возвращаемый указатель отличен отNULL.Если p не равен
NULL, он должен быть возвращен предыдущим вызовомPyMem_RawMalloc(),PyMem_RawRealloc()илиPyMem_RawCalloc().В случае ошибки
PyMem_RawRealloc()возвращаетNULL, и p остается действующим указателем на предыдущую область памяти.
-
void PyMem_RawFree(void *p)¶
- Часть Stable ABI, начиная с версии 3.13.
Освобождает блок памяти, на который указывает p. Этот указатель должен быть возвращен предыдущим вызовом
PyMem_RawMalloc(),PyMem_RawRealloc()илиPyMem_RawCalloc(). В противном случае, или еслиPyMem_RawFree(p)уже вызывался, поведение не определено.Если p равен
NULL, никаких действий не выполняется.
Интерфейс памяти¶Memory Interface
Следующие наборы функций, созданные по образцу стандарта ANSI C, но с определенным поведением при запросе нулевого количества байт, доступны для выделения и освобождения памяти из кучи Python.
В сборке с включенным GIL (сборка по умолчанию) аллокатор памяти по умолчанию использует аллокатор pymalloc, тогда как в сборке со свободными потоками по умолчанию используется аллокатор mimalloc.
Предупреждение
При использовании этих функций должно быть присоединенное состояние потока.
Изменено в версии 3.6: Аллокатором по умолчанию теперь является pymalloc вместо системного malloc().
Изменено в версии 3.13: В сборке со свободными потоками аллокатором по умолчанию теперь является mimalloc.
-
void *PyMem_Malloc(size_t n)¶
- Часть Stable ABI.
Выделяет n байт и возвращает указатель типа void* на выделенную память или
NULLв случае ошибки.Запрос нулевого количества байт возвращает отличный от
NULLуказатель, если это возможно, как если бы вместо этого был вызванPyMem_Malloc(1). Память не будет инициализирована каким-либо образом.
-
void *PyMem_Calloc(size_t nelem, size_t elsize)¶
- Часть Stable ABI начиная с версии 3.7.
Выделяет nelem элементов размером elsize байт каждый и возвращает указатель типа void* на выделенную память или
NULLв случае ошибки. Память инициализируется нулями.Запрос нулевого количества элементов или элементов нулевого размера возвращает отличный от
NULLуказатель, если это возможно, как если бы вместо этого был вызванPyMem_Calloc(1, 1).Добавлено в версии 3.5.
-
void *PyMem_Realloc(void *p, size_t n)¶
- Часть Stable ABI.
Изменяет размер блока памяти, на который указывает p, до n байт. Содержимое останется неизменным в объеме, равном минимальному из старого и нового размеров.
Если p равен
NULL, вызов эквивалентенPyMem_Malloc(n); иначе если n равен нулю, блок памяти изменяет размер, но не освобождается, и возвращаемый указатель отличен отNULL.Если p не равен
NULL, он должен быть возвращен предыдущим вызовомPyMem_Malloc(),PyMem_Realloc()илиPyMem_Calloc().В случае ошибки
PyMem_Realloc()возвращаетNULL, и p остается действующим указателем на предыдущую область памяти.
-
void PyMem_Free(void *p)¶
- Часть Stable ABI.
Освобождает блок памяти, на который указывает p. Этот указатель должен быть возвращен предыдущим вызовом
PyMem_Malloc(),PyMem_Realloc()илиPyMem_Calloc(). В противном случае, или еслиPyMem_Free(p)уже вызывался, поведение не определено.Если p равен
NULL, никаких действий не выполняется.
Для удобства предоставлены следующие макросы, ориентированные на типы. Обратите внимание, что TYPE относится к любому типу C.
-
PyMem_New(TYPE, n)¶
То же, что и
PyMem_Malloc(), но выделяет(n * sizeof(TYPE))байт памяти. Возвращает указатель, приведенный кTYPE*. Память не будет инициализирована каким-либо образом.
-
PyMem_Resize(p, TYPE, n)¶
То же, что
PyMem_Realloc(), но блок памяти изменяется до(n * sizeof(TYPE))байт. Возвращает указатель, приведённый кTYPE*. При возврате p будет указателем на новую область памяти илиNULLв случае ошибки.Это макрос препроцессора C; p всегда переназначается. Сохраняйте исходное значение p, чтобы не потерять память при обработке ошибок.
-
void PyMem_Del(void *p)¶
То же, что и
PyMem_Free().
Устаревшие псевдонимы¶Deprecated aliases
Это мягко устаревшие псевдонимы существующих функций и макросов. Они существуют исключительно для обратной совместимости.
Устаревший псевдоним |
Соответствующая функция или макрос |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
Изменено в версии 3.4: Макросы теперь являются псевдонимами соответствующих функций и макросов. Ранее их поведение было тем же, но их использование не обязательно сохраняло двоичную совместимость между версиями Python.
Устарело с версии 2.0.
Аллокаторы объектов¶Object allocators
Следующие наборы функций, основанные на стандарте ANSI C, но определяющие поведение при запросе нуля байт, доступны для выделения и освобождения памяти из кучи Python.
Примечание
Нет гарантии, что память, возвращаемая этими аллокаторами, может быть успешно приведена к объекту Python при перехвате функций выделения в этой области методами, описанными в разделе Customize Memory Allocators.
The default object allocator uses the pymalloc memory allocator. In the free-threaded build, the default is the mimalloc memory allocator instead.
Предупреждение
При использовании этих функций должно быть присоединённое состояние потока.
-
void *PyObject_Malloc(size_t n)¶
- Часть Stable ABI.
Выделяет n байт и возвращает указатель типа void* на выделенную память или
NULL, если запрос не удался.Запрос нуля байт возвращает отличный от
NULLуказатель, если это возможно, как если бы вместо этого была вызванаPyObject_Malloc(1). Память не будет инициализирована каким-либо образом.
-
void *PyObject_Calloc(size_t nelem, size_t elsize)¶
- Часть Stable ABI начиная с версии 3.7.
Выделяет nelem элементов размером elsize байт каждый и возвращает указатель типа void* на выделенную память или
NULL, если запрос не удался. Память инициализируется нулями.Запрос нуля элементов или элементов размером ноль байт возвращает отличный от
NULLуказатель, если это возможно, как если бы вместо этого была вызванаPyObject_Calloc(1, 1).Добавлено в версии 3.5.
-
void *PyObject_Realloc(void *p, size_t n)¶
- Часть Stable ABI.
Изменяет размер блока памяти, на который указывает p, до n байт. Содержимое останется неизменным в пределах меньшего из старого и нового размеров.
Если p равен
NULL, вызов эквивалентенPyObject_Malloc(n); в противном случае, если n равен нулю, размер блока памяти изменяется, но он не освобождается, и возвращаемый указатель не равенNULL.Если p не равен
NULL, он должен быть возвращён предыдущим вызовомPyObject_Malloc(),PyObject_Realloc()илиPyObject_Calloc().Если запрос не удался,
PyObject_Realloc()возвращаетNULL, а p остаётся корректным указателем на предыдущую область памяти.
-
void PyObject_Free(void *p)¶
- Часть Stable ABI.
Освобождает блок памяти, на который указывает p. Этот блок должен быть возвращён предыдущим вызовом
PyObject_Malloc(),PyObject_Realloc()илиPyObject_Calloc(). В противном случае, или если до этого был вызванPyObject_Free(p), поведение не определено.Если p равен
NULL, то никаких действий не выполняется.Не вызывайте это напрямую для освобождения памяти объекта; вместо этого вызывайте слот
tp_freeтипа.Не используйте эту функцию для памяти, выделенной
PyObject_GC_NewилиPyObject_GC_NewVar; вместо этого используйтеPyObject_GC_Del().См. также
PyObject_GC_Del()– это аналог данной функции для памяти, выделенной типами, поддерживающими сборку мусора.
Аллокаторы памяти по умолчанию¶Default Memory Allocators
Аллокаторы памяти по умолчанию:
Конфигурация |
Имя |
PyMem_RawMalloc |
PyMem_Malloc |
PyObject_Malloc |
|---|---|---|---|---|
Релизная сборка |
|
|
|
|
Отладочная сборка |
|
|
|
|
Релизная сборка, без pymalloc |
|
|
|
|
Отладочная сборка, без pymalloc |
|
|
|
|
Free-threaded сборка |
|
|
|
|
Free-threaded отладочная сборка |
|
|
|
|
Условные обозначения:
Имя: значение для переменной окружения
PYTHONMALLOC.malloc: системные аллокаторы из стандартной библиотеки C, функции языка C:malloc(),calloc(),realloc()иfree().pymalloc: аллокатор памяти pymalloc.mimalloc: аллокатор памяти mimalloc.«+ отладка»: с отладочными перехватчиками на аллокаторах памяти Python.
“Debug build”: сборка Python в режиме отладки.
Настройка распределителей памяти¶Customize Memory Allocators
Добавлено в версии 3.4.
-
type PyMemAllocatorEx¶
Структура, используемая для описания распределителя блоков памяти. Структура содержит следующие поля:
Поле
Значение
void *ctxконтекст пользователя, передаваемый в качестве первого аргумента
void* malloc(void *ctx, size_t size)выделить блок памяти
void* calloc(void *ctx, size_t nelem, size_t elsize)выделить блок памяти, инициализированный нулями
void* realloc(void *ctx, void *ptr, size_t new_size)выделить или изменить размер блока памяти
void free(void *ctx, void *ptr)освободить блок памяти
Изменено в версии 3.5: Структура
PyMemAllocatorбыла переименована вPyMemAllocatorEx, и добавлено новое полеcalloc.
-
type PyMemAllocatorDomain¶
Перечисление, используемое для идентификации домена распределителя. Домены:
-
PYMEM_DOMAIN_RAW¶
Функции:
-
PYMEM_DOMAIN_MEM¶
Функции:
-
PYMEM_DOMAIN_OBJ¶
Функции:
-
PYMEM_DOMAIN_RAW¶
-
void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)¶
Получить распределитель блоков памяти для указанного домена.
-
void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)¶
Установить распределитель блоков памяти для указанного домена.
Новый распределитель должен возвращать отличный от
NULLуказатель при запросе нулевого количества байт.Для домена
PYMEM_DOMAIN_RAWраспределитель должен быть потокобезопасным: состояние потока не присоединено при вызове распределителя.Для остальных доменов распределитель также должен быть потокобезопасным: распределитель может быть вызван в разных интерпретаторах, которые не используют общий GIL.
Если новый распределитель не является перехватчиком (не вызывает предыдущий распределитель), необходимо вызвать функцию
PyMem_SetupDebugHooks(), чтобы переустановить отладочные перехватчики поверх нового распределителя.См. также
PyPreConfig.allocatorи предварительную инициализацию Python с помощью PyPreConfig.Предупреждение
PyMem_SetAllocator()имеет следующее контрактное соглашение:It can be called after
Py_PreInitialize()and beforePy_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 an attached thread state). See the section on allocator domains for more information.Если вызывается после завершения инициализации Python (после вызова
Py_InitializeFromConfig()), распределитель должен оборачивать существующий распределитель. Замена текущего распределителя на произвольный другой не поддерживается.
Изменено в версии 3.12: Все распределители должны быть потокобезопасными.
-
void PyMem_SetupDebugHooks(void)¶
Устанавливает отладочные ловушки в распределителях памяти Python для обнаружения ошибок памяти.
Отладочные ловушки в распределителях памяти Python¶Debug hooks on the Python memory allocators
Когда Python собран в режиме отладки, функция
PyMem_SetupDebugHooks() вызывается во время преинициализации Python для установки отладочных ловушек в распределителях памяти Python
для обнаружения ошибок памяти.
Переменная окружения PYTHONMALLOC может использоваться для установки отладочных
ловушек в Python, скомпилированном в релизном режиме (например: PYTHONMALLOC=debug).
Функция PyMem_SetupDebugHooks() может использоваться для установки отладочных ловушек
после вызова PyMem_SetAllocator().
Эти отладочные ловушки заполняют динамически выделенные блоки памяти специальными,
распознаваемыми битовыми шаблонами. Вновь выделенная память заполняется байтом
0xCD (PYMEM_CLEANBYTE), освобождённая память – байтом 0xDD
(PYMEM_DEADBYTE). Блоки памяти окружены «запрещёнными байтами»,
заполненными байтом 0xFD (PYMEM_FORBIDDENBYTE). Строки из этих байтов
вряд ли являются допустимыми адресами, числами с плавающей точкой или строками ASCII.
Проверки во время выполнения:
Обнаруживает нарушения API. Например, определяет, была ли
PyObject_Free()вызвана для блока памяти, выделенного функциейPyMem_Malloc().Обнаруживает запись перед началом буфера (недополнение буфера).
Обнаруживает запись после конца буфера (переполнение буфера).
Проверяет, что присутствует привязанное состояние потока, когда вызываются функции распределителя доменов
PYMEM_DOMAIN_OBJ(например:PyObject_Malloc()) иPYMEM_DOMAIN_MEM(например:PyMem_Malloc()).
При ошибке отладочные ловушки используют модуль tracemalloc для получения
traceback'а места, где был выделен блок памяти. Traceback отображается только
в том случае, если tracemalloc отслеживает выделения памяти Python, и блок памяти
был отслежен.
Пусть S = sizeof(size_t). 2*S байтов добавляется с каждого конца каждого блока
из N запрошенных байтов. Расположение в памяти выглядит следующим образом, где p представляет
адрес, возвращаемый функцией типа malloc или realloc (p[i:j] означает
срез байтов от *(p+i) включительно до *(p+j) исключительно; обратите внимание,
что обработка отрицательных индексов отличается от среза Python):
p[-2*S:-S]Количество байтов, первоначально запрошенное. Это size_t с прямым порядком байтов (легче читать в дампе памяти).
p[-S]Идентификатор API (символ ASCII):
'r'дляPYMEM_DOMAIN_RAW.'m'дляPYMEM_DOMAIN_MEM.'o'дляPYMEM_DOMAIN_OBJ.
p[-S+1:0]Копии PYMEM_FORBIDDENBYTE. Используются для обнаружения записи и чтения до начала буфера.
p[0:N]Запрошенная память, заполненная копиями PYMEM_CLEANBYTE, используется для обнаружения ссылок на неинициализированную память. При вызове функции типа realloc с запросом большего блока памяти новые избыточные байты также заполняются PYMEM_CLEANBYTE. При вызове функции типа free эти байты перезаписываются PYMEM_DEADBYTE для обнаружения ссылок на освобождённую память. При вызове функции типа realloc с запросом меньшего блока памяти избыточные старые байты также заполняются PYMEM_DEADBYTE.
p[N:N+S]Копии PYMEM_FORBIDDENBYTE. Используются для обнаружения записи и чтения после конца буфера.
p[N+S:N+2*S]Используется только если определён макрос
PYMEM_DEBUG_SERIALNO(по умолчанию не определён).Серийный номер, увеличиваемый на 1 при каждом вызове функции типа malloc или realloc. Big-endian
size_t. Если позже будет обнаружена «плохая память», серийный номер даёт отличный способ установить точку останова при следующем запуске, чтобы зафиксировать момент, когда этот блок был выдан. Статическая функция bumpserialno() в obmalloc.c – единственное место, где серийный номер увеличивается, и она существует, чтобы можно было легко установить такую точку останова.
Функция типа realloc или free сначала проверяет, что байты PYMEM_FORBIDDENBYTE на каждом конце не повреждены. Если они были изменены, диагностический вывод записывается в stderr, и программа аварийно завершается через Py_FatalError(). Другой основной режим отказа – провоцирование ошибки памяти, когда программа читает один из специальных битовых шаблонов и пытается использовать его как адрес. Если затем войти в отладчик и посмотреть на объект, скорее всего, можно увидеть, что он полностью заполнен PYMEM_DEADBYTE (что означает использование освобождённой памяти) или PYMEM_CLEANBYTE (что означает использование неинициализированной памяти).
Изменено в версии 3.6: Функция PyMem_SetupDebugHooks() теперь также работает в Python,
скомпилированном в релизном режиме. При ошибке отладочные ловушки теперь используют
tracemalloc для получения traceback'а места, где был выделен блок памяти.
Отладочные ловушки также проверяют, есть ли привязанное состояние потока, когда
вызываются функции доменов PYMEM_DOMAIN_OBJ и PYMEM_DOMAIN_MEM.
Изменено в версии 3.8: Байтовые шаблоны 0xCB (PYMEM_CLEANBYTE), 0xDB (PYMEM_DEADBYTE)
и 0xFB (PYMEM_FORBIDDENBYTE) были заменены на 0xCD,
0xDD и 0xFD, чтобы использовать те же значения, что и отладочные malloc() и free() CRT Windows.
Распределитель pymalloc¶The pymalloc allocator
В Python есть распределитель pymalloc, оптимизированный для небольших объектов (размером меньше или равно
512 байт) с коротким временем жизни. Он использует отображения памяти, называемые «аренами»,
с фиксированным размером: 256 КиБ на 32-битных платформах или 1 МиБ на 64-битных
платформах. Если Python настроен с --with-pymalloc-hugepages,
размер арены на 64-битных платформах увеличивается до 2 МиБ для соответствия размеру больших страниц,
и выделение арен будет пытаться использовать большие страницы (MAP_HUGETLB в
Linux, MEM_LARGE_PAGES в Windows) с автоматическим возвратом к обычным страницам.
Для выделений размером более 512 байт используется PyMem_RawMalloc() и
PyMem_RawRealloc().
pymalloc – это распределитель по умолчанию для доменов
PYMEM_DOMAIN_MEM (например: PyMem_Malloc()) и
PYMEM_DOMAIN_OBJ (например: PyObject_Malloc()).
Распределитель арен использует следующие функции:
VirtualAlloc()иVirtualFree()в Windows,mmap()иmunmap(), если доступно,malloc()иfree()в противном случае.
Этот аллокатор отключается, если Python собран с опцией
--without-pymalloc. Его также можно отключить во время выполнения с помощью
переменной окружения PYTHONMALLOC (например, PYTHONMALLOC=malloc).
Обычно имеет смысл отключать аллокатор pymalloc при сборке
Python с AddressSanitizer (--with-address-sanitizer), который помогает
выявлять низкоуровневые ошибки в C-коде.
Настройка аллокатора арен pymalloc¶Customize pymalloc Arena Allocator
Добавлено в версии 3.4.
-
type PyObjectArenaAllocator¶
Структура, используемая для описания аллокатора арен. Структура содержит три поля:
Поле
Значение
void *ctxконтекст пользователя, передаваемый первым аргументом
void* alloc(void *ctx, size_t size)выделить арену размером bytes
void free(void *ctx, void *ptr, size_t size)освободить арену
-
void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)¶
Получить аллокатор арен.
-
void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)¶
Установить аллокатор арен.
Аллокатор mimalloc¶The mimalloc allocator
Добавлено в версии 3.13.
Python поддерживает аллокатор mimalloc при наличии поддержки со стороны платформы. mimalloc – это универсальный аллокатор с отличными характеристиками производительности, изначально разработанный Дааном Лейеном для сред выполнения языков Koka и Lean.
В отличие от pymalloc, оптимизированного для маленьких объектов (512 байт или меньше), mimalloc обрабатывает выделения любого размера.
В сборке free-threaded mimalloc является аллокатором по умолчанию
и обязательным для доменов PYMEM_DOMAIN_MEM и
PYMEM_DOMAIN_OBJ. Его нельзя отключить в сборках free-threaded.
В сборке free-threaded используются отдельные кучи mimalloc для каждого потока, что позволяет
выполнять выделение и освобождение без блокировок в большинстве случаев.
В сборке по умолчанию (non-free-threaded) mimalloc доступен, но не является
аллокатором по умолчанию. Его можно выбрать во время выполнения с помощью
PYTHONMALLOC=mimalloc (или mimalloc_debug для включения
отладочных хуков). Его можно отключить при сборке
с помощью опции конфигурации --without-mimalloc, но эту опцию
нельзя использовать вместе с --disable-gil.
C API tracemalloc¶tracemalloc C API
Добавлено в версии 3.7.
-
int PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, size_t size)¶
Отследить выделенный блок памяти в модуле
tracemalloc.Возвращает
0в случае успеха,-1в случае ошибки (не удалось выделить память для хранения трассировки). Возвращает-2, если tracemalloc отключен.Если блок памяти уже отслеживается, обновить существующую трассировку.
-
int PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)¶
Перестать отслеживать выделенный блок памяти в модуле
tracemalloc. Ничего не делать, если блок не отслеживался.Возвращает
-2, если tracemalloc отключен, в противном случае возвращает0.
Примеры¶Examples
Вот пример из раздела Обзор, переписанный так, чтобы буфер ввода-вывода выделялся из кучи Python с помощью первого набора функций:
PyObject *res;
char *buf = (char *) PyMem_Malloc(BUFSIZ); /* для ввода-вывода */
if (buf == NULL)
return PyErr_NoMemory();
/* ...Выполнить некоторые операции ввода-вывода с buf... */
res = PyBytes_FromString(buf);
PyMem_Free(buf); /* выделено с помощью PyMem_Malloc */
return res;
Тот же код с использованием тип-ориентированного набора функций:
PyObject *res;
char *buf = PyMem_New(char, BUFSIZ); /* для ввода-вывода */
if (buf == NULL)
return PyErr_NoMemory();
/* ...Выполнить некоторые операции ввода-вывода с buf... */
res = PyBytes_FromString(buf);
PyMem_Free(buf); /* выделено с помощью PyMem_New */
return res;
Обратите внимание, что в двух приведённых выше примерах буфер всегда обрабатывается с помощью функций из одного и того же набора. Действительно, для данного блока памяти необходимо использовать одно и то же семейство API для работы с памятью, чтобы риск смешивания разных аллокаторов был сведён к минимуму. Следующая последовательность кода содержит две ошибки, одна из которых помечена как фатальная, поскольку она смешивает два разных аллокатора, работающих с разными кучами.
char *buf1 = PyMem_New(char, BUFSIZ);
char *buf2 = (char *) malloc(BUFSIZ);
char *buf3 = (char *) PyMem_Malloc(BUFSIZ);
...
PyMem_Del(buf3); /* Неверно -- следует использовать PyMem_Free() */
free(buf2); /* Верно -- выделено через malloc() */
free(buf1); /* Фатально -- следует использовать PyMem_Free() */
В дополнение к функциям, предназначенным для работы с сырыми блоками памяти из кучи Python, объекты в Python выделяются и освобождаются с помощью PyObject_New,
PyObject_NewVar и PyObject_Free().
Они будут описаны в следующей главе, посвящённой определению и реализации новых типов объектов на C.