Управление памятью
Обзор
Управление памятью в 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). Эти домены представляют разные стратегии выделения памяти и оптимизированы для разных целей. Конкретные сведения о том, как каждый домен выделяет память и какие внутренние функции вызывает, считаются деталями реализации, но для отладки упрощённую таблицу можно найти здесь. Нет строгого требования использовать память, возвращённую функциями выделения памяти определённого домена, только для целей, указанных этим доменом (хотя это и рекомендуется). Например, можно использовать память, возвращённую PyMem_RawMalloc(), для выделения памяти под объекты Python или память, возвращённую PyObject_Malloc(), для выделения памяти под буферы.
Существуют три домена выделения памяти:
- Домен Raw: предназначен для выделения памяти под буферы общего назначения, когда выделение должно выполняться системным распределителем или когда распределитель может работать без GIL. Память запрашивается непосредственно у системы.
- Домен «Mem»: предназначен для выделения памяти под буферы Python и буферы общего назначения, когда выделение должно выполняться при удерживаемом GIL. Память берётся из частной кучи Python.
- Домен Object: предназначен для выделения памяти, принадлежащей объектам Python. Память берётся из частной кучи Python.
Для освобождения памяти, ранее выделенной функциями определённого домена, необходимо использовать соответствующие функции освобождения памяти. Например, для освобождения памяти, выделенной с помощью PyMem_Malloc(), необходимо использовать PyMem_Free().
Интерфейс сырой памяти
Следующие наборы функций являются обёртками над системным распределителем. Эти функции потокобезопасны; удерживать GIL не требуется.
Распределитель сырой памяти по умолчанию использует следующие функции: malloc(), calloc(), realloc() и free(); при запросе нулевого количества байтов вызывайте malloc(1) (или calloc(1, 1)).
Добавлено в версии 3.4.
-
void *PyMem_RawMalloc(size_t n) -
Выделяет n байт и возвращает указатель типа void* на выделенную память или
NULL, если запрос не удался.При запросе нулевого количества байтов, если возможно, возвращается отдельный ненулевой указатель (не
NULL), как если бы вместо этого был вызванPyMem_RawMalloc(1). Память не будет инициализирована каким-либо образом.
-
void *PyMem_RawCalloc(size_t nelem, size_t elsize) -
Выделяет nelem элементов размером elsize байт каждый и возвращает указатель типа void* на выделенную память или
NULL, если запрос не удался. Память инициализируется нулями.При запросе нулевого количества элементов или элементов нулевого размера, если возможно, возвращается отдельный ненулевой указатель (не
NULL), как если бы вместо этого был вызванPyMem_RawCalloc(1, 1).Добавлено в версии 3.5.
-
void *PyMem_RawRealloc(void *p, size_t n) -
Изменяет размер блока памяти, на который указывает 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) -
Освобождает блок памяти, на который указывает 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. - «+ отладка»: с отладочными перехватчиками распределителей памяти 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 распределитель может вызываться без удержания 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() CRT Windows.
Распределитель 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
Добавлено в версии 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) -
Установить распределитель арен.
API tracemalloc для C
Добавлено в версии 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/c-api/memory.html