memory.md
1> **Источник:** https://python-all.ru/2.6/c-api/memory.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Управление памятью89## Обзор1011Управление памятью в Python включает приватную кучу, содержащую все объекты и структуры данных Python. Управление этой приватной кучей внутренне обеспечивается *менеджером памяти Python*. Менеджер памяти Python имеет различные компоненты, которые занимаются разными аспектами управления динамической памятью, такими как совместное использование, сегментация, предварительное выделение или кеширование.1213На нижнем уровне сырой распределитель памяти гарантирует, что в приватной куче достаточно места для хранения всех данных Python, взаимодействуя с менеджером памяти операционной системы. Поверх сырого распределителя памяти несколько объектно-специфичных распределителей работают с той же кучей и реализуют различные политики управления памятью, адаптированные к особенностям каждого типа объектов. Например, целочисленные объекты управляются в куче иначе, чем строки, кортежи или словари, поскольку целые числа подразумевают другие требования к хранению и компромиссы между скоростью и объёмом. Таким образом, менеджер памяти Python делегирует часть работы объектно-специфичным распределителям, но следит, чтобы последние работали в границах приватной кучи.1415Важно понимать, что управление кучей Python выполняется самим интерпретатором, и пользователь не может на него повлиять, даже если он регулярно манипулирует указателями на объекты в блоках памяти внутри этой кучи. Выделение памяти кучи для объектов Python и других внутренних буферов выполняется по требованию менеджером памяти Python через функции Python/C API, перечисленные в этом документе.1617Чтобы избежать повреждения памяти, разработчикам расширений никогда не следует пытаться работать с объектами Python с помощью функций, экспортируемых библиотекой C: `malloc()`, `calloc()`, `realloc()` и `free()`. Это приведёт к смешанным вызовам между C-аллокатором и менеджером памяти Python с фатальными последствиями, поскольку они реализуют разные алгоритмы и работают с разными кучами. Однако можно безопасно выделять и освобождать блоки памяти с помощью аллокатора библиотеки C для отдельных целей, как показано в следующем примере:1819```c20PyObject *res;21char *buf = (char *) malloc(BUFSIZ); /* для ввода-вывода */2223if (buf == NULL)24 return PyErr_NoMemory();25...Do some I/O operation involving buf...26res = PyString_FromString(buf);27free(buf); /* выделено через malloc */28return res;29```3031В этом примере запрос памяти для буфера ввода-вывода обрабатывается аллокатором библиотеки C. Менеджер памяти Python участвует только в выделении строкового объекта, возвращаемого в качестве результата.3233Однако в большинстве ситуаций рекомендуется выделять память из Python-кучи, поскольку она находится под управлением менеджера памяти Python. Например, это необходимо, когда интерпретатор расширяется новыми типами объектов, написанными на C. Ещё одна причина использовать Python-кучу – желание *информировать* менеджер памяти Python о потребностях модуля расширения в памяти. Даже если запрошенная память используется исключительно для внутренних, узкоспециализированных целей, передача всех запросов памяти менеджеру памяти Python позволяет интерпретатору получать более точную картину общего объёма используемой памяти. Как следствие, при определённых обстоятельствах менеджер памяти Python может запускать или не запускать соответствующие действия, такие как сборка мусора, уплотнение памяти или другие профилактические процедуры. Обратите внимание: при использовании аллокатора из библиотеки C, как показано в предыдущем примере, выделенная память для буфера ввода-вывода полностью уходит из-под контроля менеджера памяти Python.3435## Интерфейс памяти3637Следующие наборы функций, созданные по образцу стандарта ANSI C, но определяющие поведение при запросе нулевого количества байт, доступны для выделения и освобождения памяти из кучи Python:3839**void\* `PyMem_Malloc`(size\_t *n*)**4041Выделяет4243*n*4445байт и возвращает указатель типа4647`void*`4849на выделенную память, или5051*NULL*5253, если запрос не удался. При запросе нуля байт возвращается отличный от5455*NULL*5657указатель, если это возможно, как если бы вместо него была вызвана5859`PyMem_Malloc(1)()`6061. Память не будет инициализирована каким-либо образом.6263**void\* `PyMem_Realloc`(void *\*p*, size\_t *n*)**6465Изменяет размер блока памяти, на который указывает6667*p*6869, до7071*n*7273байт. Содержимое остаётся без изменений до меньшего из старого и нового размеров. Если7475*p*7677равно7879*NULL*8081, вызов эквивалентен8283`PyMem_Malloc(n)()`8485; в противном случае, если8687*n*8889равно нулю, размер блока памяти изменяется, но блок не освобождается, и возвращаемый указатель не равен9091*NULL*9293. Если9495*p*9697не равно9899*NULL*100101, оно должно быть получено в результате предыдущего вызова102103[`PyMem_Malloc()`](https://python-all.ru/2.6/c-api/memory.html#PyMem_Malloc)104105или106107[`PyMem_Realloc()`](https://python-all.ru/2.6/c-api/memory.html#PyMem_Realloc)108109. Если запрос не удался,110111[`PyMem_Realloc()`](https://python-all.ru/2.6/c-api/memory.html#PyMem_Realloc)112113возвращает114115*NULL*116117, а118119*p*120121остаётся корректным указателем на предыдущую область памяти.122123**void `PyMem_Free`(void *\*p*)**124125Освобождает блок памяти, на который указывает126127*p*128129, который должен быть получен в результате предыдущего вызова130131[`PyMem_Malloc()`](https://python-all.ru/2.6/c-api/memory.html#PyMem_Malloc)132133или134135[`PyMem_Realloc()`](https://python-all.ru/2.6/c-api/memory.html#PyMem_Realloc)136137. В противном случае, или если138139`PyMem_Free(p)()`140141уже был вызван ранее, поведение не определено. Если142143*p*144145равно146147*NULL*148149, операция не выполняется.150151Для удобства предоставлены следующие макросы, ориентированные на типы. Обратите внимание, что *TYPE* относится к любому типу C.152153**TYPE\* `PyMem_New`(TYPE, size\_t *n*)**154155То же, что и156157[`PyMem_Malloc()`](https://python-all.ru/2.6/c-api/memory.html#PyMem_Malloc)158159, но выделяет160161`(n * sizeof(TYPE))`162163байтов памяти. Возвращает указатель, приведённый к типу164165`TYPE*`166167. Память не будет инициализирована каким-либо образом.168169**TYPE\* `PyMem_Resize`(void *\*p*, TYPE, size\_t *n*)**170171То же, что и172173[`PyMem_Realloc()`](https://python-all.ru/2.6/c-api/memory.html#PyMem_Realloc)174175, но размер блока памяти изменяется до176177`(n * sizeof(TYPE))`178179байтов. Возвращает указатель, приведённый к типу180181`TYPE*`182183. По возвращении,184185*p*186187будет указателем на новую область памяти или188189*NULL*190191в случае неудачи. Это макрос препроцессора C; p всегда переназначается. Сохраните исходное значение p, чтобы не потерять память при обработке ошибок.192193**void `PyMem_Del`(void *\*p*)**194195То же, что и196197[`PyMem_Free()`](https://python-all.ru/2.6/c-api/memory.html#PyMem_Free)198199.200201Кроме того, для прямого вызова аллокатора памяти Python, без использования перечисленных выше функций C API, предоставляются следующие наборы макросов. Однако следует учитывать, что их использование не гарантирует двоичной совместимости между версиями Python, поэтому в модулях расширения они считаются устаревшими.202203`PyMem_MALLOC()`, `PyMem_REALLOC()`, `PyMem_FREE()`.204205`PyMem_NEW()`, `PyMem_RESIZE()`, `PyMem_DEL()`.206207## Примеры208209Вот пример из раздела [*Обзор*](https://python-all.ru/2.6/c-api/memory.html#memoryoverview), переписанный так, чтобы буфер ввода-вывода выделялся из кучи Python с помощью первого набора функций:210211```c212PyObject *res;213char *buf = (char *) PyMem_Malloc(BUFSIZ); /* для ввода-вывода */214215if (buf == NULL)216 return PyErr_NoMemory();217/* ...Выполнить некоторые операции ввода-вывода с buf... */218res = PyString_FromString(buf);219PyMem_Free(buf); /* выделено с помощью PyMem_Malloc */220return res;221```222223Тот же код с использованием тип-ориентированного набора функций:224225```c226PyObject *res;227char *buf = PyMem_New(char, BUFSIZ); /* для ввода-вывода */228229if (buf == NULL)230 return PyErr_NoMemory();231/* ...Выполнить некоторые операции ввода-вывода с buf... */232res = PyString_FromString(buf);233PyMem_Del(buf); /* выделено с помощью PyMem_New */234return res;235```236237Обратите внимание, что в двух приведённых выше примерах буфер всегда обрабатывается с помощью функций из одного и того же набора. Действительно, для данного блока памяти необходимо использовать одно и то же семейство API для работы с памятью, чтобы риск смешивания разных аллокаторов был сведён к минимуму. Следующая последовательность кода содержит две ошибки, одна из которых помечена как *фатальная*, поскольку она смешивает два разных аллокатора, работающих с разными кучами.238239```c240char *buf1 = PyMem_New(char, BUFSIZ);241char *buf2 = (char *) malloc(BUFSIZ);242char *buf3 = (char *) PyMem_Malloc(BUFSIZ);243...244PyMem_Del(buf3); /* Неверно -- следует использовать PyMem_Free() */245free(buf2); /* Верно -- выделено через malloc() */246free(buf1); /* Фатальная ошибка – следует использовать PyMem_Del() */247```248249In addition to the functions aimed at handling raw memory blocks from the Python heap, objects in Python are allocated and released with [`PyObject_New()`](https://python-all.ru/2.6/c-api/allocation.html#PyObject_New), [`PyObject_NewVar()`](https://python-all.ru/2.6/c-api/allocation.html#PyObject_NewVar) and [`PyObject_Del()`](https://python-all.ru/2.6/c-api/allocation.html#PyObject_Del).250251Они будут описаны в следующей главе, посвящённой определению и реализации новых типов объектов на C.252