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

Обзор

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

malloc

pymalloc

pymalloc

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

"pymalloc_debug"

malloc + отладка

pymalloc + отладка

pymalloc + отладка

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

"malloc"

malloc

malloc

malloc

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

"malloc_debug"

malloc + отладка

malloc + отладка

malloc + отладка

Легенда:

Настройка распределителей памяти

Добавлено в версии 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.

Вернуться на верх