Spec-Zone.ru › Python 3.12

Управление памятью

Обзор

Управление памятью в 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"

malloc

pymalloc

pymalloc

Отладочная сборка

"pymalloc_debug"

malloc + отладка

pymalloc + отладка

pymalloc + отладка

Релизная сборка без pymalloc

"malloc"

malloc

malloc

malloc

Отладочная сборка без pymalloc

"malloc_debug"

malloc + отладка

malloc + отладка

malloc + отладка

Условные обозначения:

  • Название: значение переменной среды 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_RawMalloc()
  • PyMem_RawRealloc()
  • PyMem_RawCalloc()
  • PyMem_RawFree()
PYMEM_DOMAIN_MEM

Функции:

  • PyMem_Malloc(),
  • PyMem_Realloc()
  • PyMem_Calloc()
  • PyMem_Free()
PYMEM_DOMAIN_OBJ

Функции:

  • PyObject_Malloc()
  • PyObject_Realloc()
  • PyObject_Calloc()
  • PyObject_Free()
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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API