Управление памятью¶
Обзор¶
Управление памятью в 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 memory allocator при каждом создании новой арены объекта pymalloc, а также при выключении.
Домены-распределители¶
Все функции выделения принадлежат к одному из трех различных «доменов» (см. также PyMemAllocatorDomain
). Эти домены представляют различные стратегии выделения и оптимизированы для различных целей. Конкретные детали того, как каждый домен выделяет память или какие внутренние функции вызывает каждый домен, считаются деталями реализации, но для целей отладки упрощенная таблица может быть найдена в here. Нет жесткого требования использовать память, возвращаемую функциями выделения, принадлежащими данному домену, только для тех целей, на которые намекает этот домен (хотя это рекомендуемая практика). Например, можно использовать память, возвращаемую PyMem_RawMalloc()
для выделения объектов Python или память, возвращаемую PyObject_Malloc()
для выделения памяти под буферы.
Три домена распределения - это:
Raw domain: предназначен для выделения памяти для буферов памяти общего назначения, где выделение должно идти системному аллокатору или где аллокатор может работать без GIL. Память запрашивается непосредственно у системы.
Домен «Mem»: предназначен для выделения памяти для буферов Python и буферов памяти общего назначения, где выделение должно выполняться с удержанием GIL. Память берется из частной кучи Python.
Объектный домен: предназначен для выделения памяти, принадлежащей объектам Python. Память берется из частной кучи Python.
При освобождении памяти, ранее выделенной функциями выделения, относящимися к данному домену, необходимо использовать соответствующие специфические функции деаллокации. Например, для освобождения памяти, выделенной с помощью :c<PyMem_Free()
, необходимо использовать PyMem_Malloc()
.
Интерфейс необработанной памяти¶
Следующие наборы функций являются обертками для системного аллокатора. Эти функции потокобезопасны, удерживать GIL не нужно.
default raw memory allocator использует следующие функции: 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, но определяющие поведение при запросе нулевого байта.
В default memory allocator используется pymalloc memory allocator.
Предупреждение
При использовании этих функций необходимо удерживать GIL.
Изменено в версии 3.6: Аллокатором по умолчанию теперь является pymalloc вместо системного malloc()
.
-
void *
PyMem_Malloc
(size_t n)¶ - Part of the Stable ABI.
Выделяет n байт и возвращает указатель типа void* на выделенную память, или
NULL
, если запрос не удался.Запрос нулевого байта возвращает, по возможности, отдельный не``NULL`` указатель, как если бы вместо него был вызван
PyMem_Malloc(1)
. Память не будет инициализирована никаким образом.
-
void *
PyMem_Calloc
(size_t nelem, size_t elsize)¶ - Part of the Stable ABI since version 3.7.
Выделяет элементы nelem, размер каждого из которых в байтах равен elsize, и возвращает указатель типа void* на выделенную память, или
NULL
, если запрос не удался. Память инициализируется нулями.Запрос нулевых элементов или элементов размером ноль байт возвращает, если возможно, отдельный не``NULL`` указатель, как если бы вместо него был вызван
PyMem_Calloc(1, 1)
.Добавлено в версии 3.5.
-
void *
PyMem_Realloc
(void *p, size_t n)¶ - Part of the 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)¶ - Part of the Stable ABI.
Освобождает блок памяти, на который указывает p, который должен быть возвращен предыдущим вызовом
PyMem_Malloc()
,PyMem_Realloc()
илиPyMem_Calloc()
. В противном случае, или еслиPyMem_Free(p)
был вызван ранее, произойдет неопределенное поведение.Если p равно
NULL
, операция не выполняется.
Следующие макросы, ориентированные на типы, предоставляются для удобства. Обратите внимание, что TYPE относится к любому типу языка Си.
-
TYPE *
PyMem_New
(TYPE, size_t n)¶ Аналогично
PyMem_Malloc()
, но выделяет(n * sizeof(TYPE))
байт памяти. Возвращает указатель, приведенный к TYPE*. Память не будет инициализирована никаким образом.
-
TYPE *
PyMem_Resize
(void *p, TYPE, size_t n)¶ Аналогично
PyMem_Realloc()
, но размер блока памяти изменяется до(n * sizeof(TYPE))
байт. Возвращает указатель, приведенный к TYPE*. По возвращении p будет указателем на новую область памяти, илиNULL
в случае неудачи.Это макрос препроцессора языка Си; 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 при перехвате функций аллокации в этом домене методами, описанными в разделе Customize Memory Allocators.
В default object allocator используется pymalloc memory allocator.
Предупреждение
При использовании этих функций необходимо удерживать GIL.
-
void *
PyObject_Malloc
(size_t n)¶ - Part of the Stable ABI.
Выделяет n байт и возвращает указатель типа void* на выделенную память, или
NULL
, если запрос не удался.Запрос нулевого байта возвращает, по возможности, отдельный не``NULL`` указатель, как если бы вместо него был вызван
PyObject_Malloc(1)
. Память не будет инициализирована никаким образом.
-
void *
PyObject_Calloc
(size_t nelem, size_t elsize)¶ - Part of the Stable ABI since version 3.7.
Выделяет элементы nelem, размер каждого из которых в байтах равен elsize, и возвращает указатель типа void* на выделенную память, или
NULL
, если запрос не удался. Память инициализируется нулями.Запрос нулевых элементов или элементов размером ноль байт возвращает, если возможно, отдельный не``NULL`` указатель, как если бы вместо него был вызван
PyObject_Calloc(1, 1)
.Добавлено в версии 3.5.
-
void *
PyObject_Realloc
(void *p, size_t n)¶ - Part of the 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)¶ - Part of the Stable 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 memory allocator.«+ debug»: с debug hooks on the Python memory allocators.
«Отладочная сборка»: Python build in debug mode.
Настройка распределителей памяти¶
Добавлено в версии 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 не удерживается при вызове аллокатора.Если новый аллокатор не является хуком (не вызывает предыдущий аллокатор), необходимо вызвать функцию
PyMem_SetupDebugHooks()
для переустановки отладочных хуков поверх нового аллокатора.
-
void
PyMem_SetupDebugHooks
(void)¶ Настройте debug hooks in the Python memory allocators для обнаружения ошибок памяти.
Отладочные крючки для распределителей памяти Python¶
Когда Python is built in debug mode, функция PyMem_SetupDebugHooks()
вызывается в Python preinitialization для установки отладочных крючков на распределителях памяти Python для обнаружения ошибок памяти.
Переменная окружения PYTHONMALLOC
может использоваться для установки отладочных хуков на Python, скомпилированный в режиме release (например: 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)
. Байты 2*S
добавляются с каждого конца каждого блока из N запрашиваемых байт. Схема памяти выглядит следующим образом, где p представляет собой адрес, возвращаемый malloc-подобной или realloc-подобной функцией (p[i:j]
означает срез байтов от *(p+i)
включительно до *(p+j)
включительно; обратите внимание, что обработка отрицательных индексов отличается от среза в Python):
p[-2*S:-S]
Количество байт, запрошенных изначально. Это size_t, big-endian (легче читать в дампе памяти).
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, скомпилированном в режиме release. При ошибке отладочные хуки теперь используют tracemalloc
для получения трассировки, где был выделен блок памяти. Отладочные хуки теперь также проверяют, удерживается ли GIL при вызове функций доменов PYMEM_DOMAIN_OBJ
и PYMEM_DOMAIN_MEM
.
Изменено в версии 3.8: Байтовые шаблоны 0xCB
(PYMEM_CLEANBYTE
), 0xDB
(PYMEM_DEADBYTE
) и 0xFB
(PYMEM_FORBIDDENBYTE
) были заменены на 0xCD
, 0xDD
и 0xFD
, чтобы использовать те же значения, что и Windows CRT debug malloc()
и free()
.
Распределитель pymalloc¶
В Python есть распределитель pymalloc, оптимизированный для небольших объектов (меньше или равных 512 байт) с коротким временем жизни. Он использует отображения памяти, называемые «аренами», с фиксированным размером 256 килобайт. Он возвращается к PyMem_RawMalloc()
и PyMem_RawRealloc()
для выделений размером более 512 байт.
pymalloc - это default allocator доменов 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)
выделить арену размером в байт
void free(void *ctx, void *ptr, size_t size)
освободить арену
-
void
PyObject_GetArenaAllocator
(PyObjectArenaAllocator *allocator)¶ Получить распределитель арены.
-
void
PyObject_SetArenaAllocator
(PyObjectArenaAllocator *allocator)¶ Установите распределитель арены.
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
.
Примеры¶
Вот пример из раздела Обзор, переписанный так, что буфер ввода-вывода выделяется из кучи 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.