Управление памятью
Обзор
Управление памятью в Python включает частную кучу, содержащую все объекты и структуры данных 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); /* for I/O */
if (buf == NULL)
return PyErr_NoMemory();
...Do some I/O operation involving buf...
res = PyBytes_FromString(buf);
free(buf); /* malloc'ed */
return res;
В этом примере запрос памяти для буфера ввода-вывода обрабатывается распределителем библиотеки C. Менеджер памяти Python участвует только в выделении объекта bytes, возвращаемого в результате.
Однако в большинстве случаев рекомендуется выделять память из кучи Python, поскольку она находится под контролем менеджера памяти Python. Например, это необходимо при расширении интерпретатора новыми типами объектов, написанными на C. Ещё одна причина использовать кучу Python — желание сообщить менеджеру памяти Python о потребностях модуля расширения в памяти. Даже если запрошенная память используется исключительно для внутренних, узкоспециализированных целей, передача всех запросов памяти менеджеру памяти Python позволяет интерпретатору точнее оценивать общий объём используемой им памяти. В результате при определённых обстоятельствах менеджер памяти Python может запускать или не запускать соответствующие действия, например сборку мусора, уплотнение памяти или другие профилактические процедуры. Обратите внимание: при использовании распределителя библиотеки C, как в предыдущем примере, выделенная для буфера ввода-вывода память полностью остаётся вне контроля менеджера памяти Python.
См. также
Переменную окружения PYTHONMALLOC можно использовать для настройки распределителей памяти, применяемых Python.
Переменную окружения PYTHONMALLOCSTATS можно использовать для вывода статистики распределителя памяти pymalloc при каждом создании новой арены объектов pymalloc, а также при завершении работы.
Домены распределения памяти
Все функции выделения памяти относятся к одному из трёх различных «доменов» (см. также PyMemAllocatorDomain). Эти домены представляют разные стратегии выделения памяти и оптимизированы для разных целей. Конкретные сведения о том, как каждый домен выделяет память и какие внутренние функции вызывает, считаются деталями реализации; однако для отладки упрощённую таблицу можно найти здесь. API, используемые для выделения и освобождения блока памяти, должны принадлежать одному и тому же домену. Например, для освобождения памяти, выделенной с помощью PyMem_Malloc(), необходимо использовать PyMem_Free().
Существуют три домена выделения памяти:
- Домен Raw: предназначен для выделения памяти под буферы общего назначения, когда выделение должно выполняться системным распределителем или когда распределитель может работать без GIL. Память запрашивается непосредственно у системы. См. Интерфейс необработанной памяти.
- Домен «Mem»: предназначен для выделения памяти под буферы Python и буферы общего назначения, когда выделение должно выполняться при удерживаемом GIL. Память берётся из частной кучи Python. См. Интерфейс памяти.
- Домен объектов: предназначен для выделения памяти под объекты Python. Память берётся из частной кучи Python. См. Распределители объектов.
Примечание
Сборка с поддержкой свободной многопоточности требует, чтобы с использованием домена «object» выделялась память только для объектов Python и чтобы память для всех объектов Python выделялась именно в этом домене. Это отличается от предыдущих версий Python, где это было лишь рекомендацией, а не строгим требованием.
Например, буферы (не являющиеся объектами Python) следует выделять с помощью PyMem_Malloc(), PyMem_RawMalloc() или malloc(), но не с помощью PyObject_Malloc().
См. API выделения памяти.
Интерфейс необработанной памяти
Следующие наборы функций являются обёртками для системного распределителя. Эти функции потокобезопасны; удерживать GIL не требуется.
Распределитель необработанной памяти по умолчанию использует следующие функции: malloc(), calloc(), realloc() и free(); при запросе нулевого количества байтов вызывайте malloc(1) (или calloc(1, 1)).
Добавлено в версии 3.4.
-
void *PyMem_RawMalloc(size_t n) -
Входит в стабильный ABI начиная с версии 3.13.
Выделяет n байт и возвращает указатель типа void* на выделенную память или
NULL, если запрос не выполнен.При запросе нулевого количества байтов возвращается отдельный указатель, отличный от
NULL, если это возможно, как если бы вместо этого был вызванPyMem_RawMalloc(1). Память не будет инициализирована.
-
void *PyMem_RawCalloc(size_t nelem, size_t elsize) -
Входит в стабильный ABI начиная с версии 3.13.
Выделяет nelem элементов размером elsize байт каждый и возвращает указатель типа void* на выделенную память или
NULL, если запрос не выполнен. Память инициализируется нулями.При запросе нулевого количества элементов или элементов нулевого размера возвращается отдельный указатель, отличный от
NULL, если это возможно, как если бы вместо этого был вызванPyMem_RawCalloc(1, 1).Добавлено в версии 3.5.
-
void *PyMem_RawRealloc(void *p, size_t n) -
Входит в стабильный 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) -
Входит в стабильный ABI начиная с версии 3.13.
Освобождает блок памяти, на который указывает p. Этот блок должен быть получен в результате предыдущего вызова
PyMem_RawMalloc(),PyMem_RawRealloc()илиPyMem_RawCalloc(). В противном случае, а также если ранее был вызванPyMem_RawFree(p), поведение не определено.Если p имеет значение
NULL, операция не выполняется.
Интерфейс памяти
Для выделения и освобождения памяти в куче Python доступны следующие наборы функций, созданные по образцу стандарта ANSI C, но с заданным поведением при запросе нулевого количества байтов.
Распределитель памяти по умолчанию использует распределитель памяти pymalloc.
Предупреждение
При использовании этих функций необходимо удерживать GIL.
Изменено в версии 3.6: теперь по умолчанию используется pymalloc вместо системного malloc().
-
void *PyMem_Malloc(size_t n) -
Входит в стабильный ABI.
Выделяет n байт и возвращает указатель типа void* на выделенную память или
NULL, если запрос не выполнен.При запросе нулевого количества байтов возвращается отдельный указатель, отличный от
NULL, если это возможно, как если бы вместо этого был вызванPyMem_Malloc(1). Память не будет инициализирована.
-
void *PyMem_Calloc(size_t nelem, size_t elsize) -
Входит в стабильный ABI начиная с версии 3.7.
Выделяет nelem элементов размером elsize байт каждый и возвращает указатель типа void* на выделенную память или
NULL, если запрос не выполнен. Память инициализируется нулями.При запросе нулевого количества элементов или элементов нулевого размера возвращается отдельный указатель, отличный от
NULL, если это возможно, как если бы вместо этого был вызванPyMem_Calloc(1, 1).Добавлено в версии 3.5.
-
void *PyMem_Realloc(void *p, size_t n) -
Входит в стабильный 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) -
Входит в стабильный 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().
Кроме того, предусмотрены следующие наборы макросов для прямого вызова распределителя памяти Python без использования перечисленных выше функций C API. Однако обратите внимание, что их применение не сохраняет двоичную совместимость между версиями Python, поэтому в модулях расширений они считаются устаревшими.
PyMem_MALLOC(size)PyMem_NEW(type, size)PyMem_REALLOC(ptr, size)PyMem_RESIZE(ptr, type, size)PyMem_FREE(ptr)PyMem_DEL(ptr)
Распределители объектов
Для выделения и освобождения памяти в куче Python доступны следующие наборы функций, созданные по образцу стандарта ANSI C, но с заданным поведением при запросе нулевого количества байтов.
Примечание
Нет гарантии, что память, возвращённую этими распределителями, можно успешно привести к типу объекта Python при перехвате функций выделения памяти в этом домене с помощью методов, описанных в разделе Настройка распределителей памяти.
Распределитель объектов по умолчанию использует распределитель памяти pymalloc.
Предупреждение
При использовании этих функций необходимо удерживать GIL.
-
void *PyObject_Malloc(size_t n) -
Входит в стабильный ABI.
Выделяет n байт и возвращает указатель типа void* на выделенную память или
NULL, если запрос не выполнен.При запросе нулевого количества байтов возвращается отдельный указатель, отличный от
NULL, если это возможно, как если бы вместо этого был вызванPyObject_Malloc(1). Память не будет инициализирована.
-
void *PyObject_Calloc(size_t nelem, size_t elsize) -
Входит в стабильный ABI начиная с версии 3.7.
Выделяет nelem элементов размером elsize байт каждый и возвращает указатель типа void* на выделенную память или
NULL, если запрос не выполнен. Память инициализируется нулями.При запросе нулевого количества элементов или элементов нулевого размера возвращается отдельный указатель, отличный от
NULL, если это возможно, как если бы вместо этого был вызванPyObject_Calloc(1, 1).Добавлено в версии 3.5.
-
void *PyObject_Realloc(void *p, size_t n) -
Входит в стабильный 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) -
Входит в стабильный ABI.
Освобождает блок памяти, на который указывает p. Этот блок должен быть получен в результате предыдущего вызова
PyObject_Malloc(),PyObject_Realloc()илиPyObject_Calloc(). В противном случае, а также если ранее был вызванPyObject_Free(p), поведение не определено.Если p имеет значение
NULL, операция не выполняется.
Распределители памяти по умолчанию
Распределители памяти по умолчанию:
Конфигурация | Имя | PyMem_RawMalloc | PyMem_Malloc | PyObject_Malloc |
|---|---|---|---|---|
Сборка для выпуска |
|
|
|
|
Отладочная сборка |
|
|
|
|
Сборка для выпуска без pymalloc |
|
|
|
|
Отладочная сборка без pymalloc |
|
|
|
|
Обозначения:
- Имя: значение переменной окружения
PYTHONMALLOC. -
malloc: системные распределители из стандартной библиотеки C; функции C:malloc(),calloc(),realloc()иfree(). -
pymalloc: распределитель памяти pymalloc. -
mimalloc: распределитель памяти mimalloc. Если поддержка mimalloc недоступна, будет использоваться распределитель pymalloc. - «+ отладка»: включены отладочные перехватчики распределителей памяти Python.
- «Отладочная сборка»: сборка Python в режиме отладки.
Настройка распределителей памяти
Добавлено в версии 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 -
Функции:
-
-
void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) -
Получить распределитель блоков памяти для указанной области.
-
void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) -
Установить распределитель блоков памяти для указанной области.
При запросе нуля байт новый распределитель должен возвращать отличный от
NULLуказатель.Для области
PYMEM_DOMAIN_RAWраспределитель должен быть потокобезопасным: при вызове распределителя GIL не удерживается.Для остальных областей распределитель также должен быть потокобезопасным: его могут вызывать разные интерпретаторы, которые не используют общую
GIL.Если новый распределитель не является перехватчиком (не вызывает предыдущий распределитель), необходимо вызвать функцию
PyMem_SetupDebugHooks(), чтобы повторно установить отладочные перехватчики поверх нового распределителя.См. также
PyPreConfig.allocatorи Предварительная инициализация Python с помощью PyPreConfig.Предупреждение
Функция
PyMem_SetAllocator()имеет следующие ограничения:- Её можно вызвать после
Py_PreInitialize()и доPy_InitializeFromConfig(), чтобы установить пользовательский распределитель памяти. Для установленного распределителя нет ограничений, кроме тех, что накладываются областью (например, в Raw Domain распределитель может вызываться без удержания GIL). Дополнительные сведения см. в разделе об областях распределителей. - Если вызвать её после завершения инициализации Python (после вызова
Py_InitializeFromConfig()), распределитель должен оборачивать существующий распределитель. Подмена текущего распределителя каким-либо произвольным не поддерживается.
Изменено в версии 3.12: Все распределители должны быть потокобезопасными.
- Её можно вызвать после
-
void PyMem_SetupDebugHooks(void) -
Настроить отладочные перехватчики в распределителях памяти Python для обнаружения ошибок памяти.
Отладочные перехватчики в распределителях памяти Python
Когда 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(). - Обнаружение записи перед началом буфера (переполнение буфера снизу).
- Обнаружение записи за концом буфера (переполнение буфера сверху).
- Проверка, что GIL удерживается при вызове функций распределителей в областях
PYMEM_DOMAIN_OBJ(например,PyObject_Malloc()) иPYMEM_DOMAIN_MEM(например,PyMem_Malloc()).
При возникновении ошибки отладочные перехватчики используют модуль tracemalloc, чтобы получить трассировку стека места выделения блока памяти. Трассировка отображается только в том случае, если tracemalloc отслеживает выделение памяти Python и блок памяти отслеживался.
Пусть S = sizeof(size_t). С каждой стороны каждого запрошенного блока размером N байт добавляется 2*S байт. Расположение памяти выглядит следующим образом, где 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.
size_tв порядке от старшего байта к младшему. Если позднее обнаруживается «повреждённая память», порядковый номер позволяет легко установить точку останова при следующем запуске и зафиксировать момент, когда этот блок был передан вызывающему коду. Статическая функция bumpserialno() в obmalloc.c — единственное место, где увеличивается порядковый номер; она существует, чтобы упростить установку такой точки останова.
Функция типа realloc или free сначала проверяет, что байты PYMEM_FORBIDDENBYTE с обеих сторон блока не изменены. Если они изменены, диагностическое сообщение выводится в stderr, а программа аварийно завершается с помощью Py_FatalError(). Другой основной тип сбоя — ошибка памяти, возникающая, когда программа считывает один из специальных битовых шаблонов и пытается использовать его как адрес. Если в этот момент вы подключитесь к отладчику и посмотрите на объект, то, вероятно, увидите, что он полностью заполнен PYMEM_DEADBYTE (то есть используется освобождённая память) или PYMEM_CLEANBYTE (то есть используется неинициализированная память).
Изменено в версии 3.6: Функция PyMem_SetupDebugHooks() теперь работает и в Python, скомпилированном в режиме выпуска. При ошибке отладочные перехватчики теперь используют tracemalloc, чтобы получить трассировку стека места выделения блока памяти. Отладочные перехватчики теперь также проверяют, удерживается ли GIL при вызове функций в областях PYMEM_DOMAIN_OBJ и PYMEM_DOMAIN_MEM.
Изменено в версии 3.8: Байтовые шаблоны 0xCB (PYMEM_CLEANBYTE), 0xDB (PYMEM_DEADBYTE) и 0xFB (PYMEM_FORBIDDENBYTE) заменены на 0xCD, 0xDD и 0xFD, чтобы использовать те же значения, что и отладочные malloc() и free() Windows CRT.
Распределитель pymalloc
В Python есть распределитель pymalloc, оптимизированный для небольших объектов (размером не более 512 байт) с коротким временем жизни. Он использует отображения памяти, называемые «аренами», фиксированного размера: 256 КиБ на 32-разрядных платформах или 1 МиБ на 64-разрядных платформах. Для блоков размером более 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
Добавлено в версии 3.4.
-
type PyObjectArenaAllocator -
Структура, используемая для описания распределителя арен. Структура содержит три поля:
Поле
Значение
void *ctxпользовательский контекст, передаваемый в качестве первого аргумента
void* alloc(void *ctx, size_t size)выделить арену размером size байт
void free(void *ctx, void *ptr, size_t size)освободить арену
-
void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator) -
Получить распределитель арен.
-
void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator) -
Установить распределитель арен.
Распределитель mimalloc
Добавлено в версии 3.13.
Python поддерживает распределитель mimalloc, если это позволяет базовая платформа. mimalloc «представляет собой распределитель общего назначения с отличными характеристиками производительности. Изначально он был разработан Дааном Лейеном для систем выполнения языков Koka и Lean».
C API tracemalloc
Добавлено в версии 3.7.
-
int PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, size_t size) -
Отслеживать выделенный блок памяти в модуле
tracemalloc.В случае успеха возвращает
0, в случае ошибки (не удалось выделить память для хранения трассировки) —-1. Если tracemalloc отключён, возвращает-2.Если блок памяти уже отслеживается, обновляет существующую трассировку.
-
int PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr) -
Прекратить отслеживание выделенного блока памяти в модуле
tracemalloc. Ничего не делать, если блок не отслеживался.Если tracemalloc отключён, возвращает
-2, в противном случае —0.
Примеры
Ниже приведён пример из раздела Обзор, переписанный так, чтобы буфер ввода-вывода выделялся в куче Python с помощью первого набора функций:
PyObject *res;
char *buf = (char *) PyMem_Malloc(BUFSIZ); /* for I/O */
if (buf == NULL)
return PyErr_NoMemory();
/* ...Do some I/O operation involving buf... */
res = PyBytes_FromString(buf);
PyMem_Free(buf); /* allocated with PyMem_Malloc */
return res;
Тот же код с использованием набора функций, ориентированного на типы:
PyObject *res;
char *buf = PyMem_New(char, BUFSIZ); /* for I/O */
if (buf == NULL)
return PyErr_NoMemory();
/* ...Do some I/O operation involving buf... */
res = PyBytes_FromString(buf);
PyMem_Del(buf); /* allocated with PyMem_New */
return res;
Обратите внимание, что в двух приведённых выше примерах буфер всегда обрабатывается функциями из одного и того же набора. Для каждого блока памяти необходимо использовать одно и то же семейство API памяти, чтобы свести к минимуму риск смешивания разных распределителей. Следующая последовательность кода содержит две ошибки; одна из них помечена как фатальная, поскольку в ней смешиваются два разных распределителя, работающих с разными кучами.
char *buf1 = PyMem_New(char, BUFSIZ); char *buf2 = (char *) malloc(BUFSIZ); char *buf3 = (char *) PyMem_Malloc(BUFSIZ); ... PyMem_Del(buf3); /* Wrong -- should be PyMem_Free() */ free(buf2); /* Right -- allocated via malloc() */ free(buf1); /* Fatal -- should be PyMem_Del() */
Помимо функций для работы с необработанными блоками памяти из кучи Python, объекты в Python выделяются и освобождаются с помощью PyObject_New, PyObject_NewVar и PyObject_Del().
Эти функции будут описаны в следующей главе, посвящённой определению и реализации новых типов объектов на C.
© 2001–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/c-api/memory.html