Документация Python неофициальный перевод

memory.md

169 строк · 19.6 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/2.7/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Выделяет *n* байт и возвращает указатель типа `void*` на выделенную память или *NULL* в случае неудачи. Запрос нуля байт возвращает отдельный ненулевой указатель *NULL*, если это возможно, как если бы вместо него был вызван `PyMem_Malloc(1)`. Память не инициализируется.4243#### `void* PyMem_Realloc(void *p, size_t n)`4445Изменяет размер блока памяти, на который указывает *p*, до *n* байт. Содержимое остаётся неизменным до меньшего из старого и нового размеров. Если *p* равен *NULL*, вызов эквивалентен `PyMem_Malloc(n)`; если *n* равно нулю, размер блока памяти изменяется, но он не освобождается, и возвращаемый указатель не равен *NULL*. Если *p* не равен *NULL*, он должен быть возвращён предыдущим вызовом [`PyMem_Malloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyMem_Malloc) или [`PyMem_Realloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyMem_Realloc). В случае неудачи [`PyMem_Realloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyMem_Realloc) возвращает *NULL*, а *p* остаётся корректным указателем на предыдущую область памяти.4647#### `void PyMem_Free(void *p)`4849Освобождает блок памяти, на который указывает *p*, который должен быть возвращён предыдущим вызовом [`PyMem_Malloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyMem_Malloc) или [`PyMem_Realloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyMem_Realloc). В противном случае или если `PyMem_Free(p)` уже был вызван ранее, возникает неопределённое поведение. Если *p* равен *NULL*, операция не выполняется.5051Для удобства предоставлены следующие макросы, ориентированные на типы. Обратите внимание, что *TYPE* относится к любому типу C.5253#### `TYPE* PyMem_New(TYPE, size_t n)`5455То же, что и [`PyMem_Malloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyMem_Malloc), но выделяет `(n * sizeof(TYPE))` байт памяти. Возвращает указатель, приведенный к `TYPE*`. Память не будет инициализирована каким-либо образом.5657#### `TYPE* PyMem_Resize(void *p, TYPE, size_t n)`5859То же, что и [`PyMem_Realloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyMem_Realloc), но размер блока памяти изменяется до `(n * sizeof(TYPE))` байт. Возвращает указатель, приведённый к `TYPE*`. После возврата *p* будет указателем на новую область памяти или *NULL* в случае неудачи. Это макрос препроцессора C; p всегда переприсваивается. Сохраните исходное значение p, чтобы избежать потери памяти при обработке ошибок.6061#### `void PyMem_Del(void *p)`6263То же, что и [`PyMem_Free()`](https://python-all.ru/2.7/c-api/memory.html#c.PyMem_Free).6465Кроме того, для прямого вызова аллокатора памяти Python, без использования перечисленных выше функций C API, предоставляются следующие наборы макросов. Однако следует учитывать, что их использование не гарантирует двоичной совместимости между версиями Python, поэтому в модулях расширения они считаются устаревшими.6667`PyMem_MALLOC()`, `PyMem_REALLOC()`, `PyMem_FREE()`.6869`PyMem_NEW()`, `PyMem_RESIZE()`, `PyMem_DEL()`.7071## Аллокаторы объектов7273Следующие наборы функций, основанные на стандарте ANSI C, но определяющие поведение при запросе нуля байт, доступны для выделения и освобождения памяти из кучи Python.7475По умолчанию эти функции используют [аллокатор памяти pymalloc](https://python-all.ru/2.7/c-api/memory.html#pymalloc).7677> **Предупреждение**78>79> При использовании этих функций необходимо удерживать [GIL](https://python-all.ru/2.7/glossary.html#term-global-interpreter-lock).8081#### `void* PyObject_Malloc(size_t n)`8283Выделяет *n* байт и возвращает указатель типа `void*` на выделенную память или *NULL* в случае неудачи.8485Запрос нулевого количества байт возвращает отличный от *NULL* указатель, если это возможно, как если бы вместо этого была вызвана `PyObject_Malloc(1)`. Память не будет инициализирована никаким образом.8687#### `void* PyObject_Realloc(void *p, size_t n)`8889Изменяет размер блока памяти, на который указывает *p*, до *n* байт. Содержимое останется неизменным в пределах меньшего из старого и нового размеров.9091Если *p* равно *NULL*, вызов эквивалентен `PyObject_Malloc(n)`; в противном случае, если *n* равно нулю, блок памяти изменяет размер, но не освобождается, и возвращаемый указатель не равен *NULL*.9293Если *p* не равно *NULL*, то он должен быть возвращен предыдущим вызовом [`PyObject_Malloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Malloc), [`PyObject_Realloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Realloc) или `PyObject_Calloc()`.9495Если запрос не удался, [`PyObject_Realloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Realloc) возвращает *NULL*, а *p* остается действительным указателем на предыдущую область памяти.9697#### `void PyObject_Free(void *p)`9899Освобождает блок памяти, на который указывает *p*. Этот блок должен быть возвращён предыдущим вызовом [`PyObject_Malloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Malloc), [`PyObject_Realloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Realloc) или `PyObject_Calloc()`. В противном случае, или если до этого был вызван `PyObject_Free(p)`, поведение не определено.100101Если *p* равно *NULL*, никаких действий не выполняется.102103Кроме того, предоставляются следующие наборы макросов:104105- `PyObject_MALLOC()`: псевдоним для [`PyObject_Malloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Malloc)106- `PyObject_REALLOC()`: псевдоним для [`PyObject_Realloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Realloc)107- `PyObject_FREE()`: псевдоним для [`PyObject_Free()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Free)108- [`PyObject_Del()`](https://python-all.ru/2.7/c-api/allocation.html#c.PyObject_Del): псевдоним для [`PyObject_Free()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Free)109- `PyObject_DEL()`: псевдоним для `PyObject_FREE()` (таким образом, в итоге псевдоним для [`PyObject_Free()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Free))110111## Распределитель pymalloc112113В Python имеется аллокатор *pymalloc*, оптимизированный для небольших объектов (размером не более 512 байт) с коротким временем жизни. Он использует отображения памяти, называемые «аренами», фиксированного размера 256 Кб. Для выделений более 512 байт он переключается на `malloc()` и `realloc()`.114115*pymalloc* – распределитель по умолчанию для [`PyObject_Malloc()`](https://python-all.ru/2.7/c-api/memory.html#c.PyObject_Malloc).116117Распределитель арен использует следующие функции:118119- `mmap()` и `munmap()`, если доступно,120- `malloc()` и `free()` в противном случае.121122Изменено в версии 2.7.7: Порог изменён с 256 до 512 байт. Распределитель арен теперь использует `mmap()`, если он доступен.123124## Примеры125126Вот пример из раздела [Обзор](https://python-all.ru/2.7/c-api/memory.html#memoryoverview), переписанный так, чтобы буфер ввода-вывода выделялся из кучи Python с помощью первого набора функций:127128```c129PyObject *res;130char *buf = (char *) PyMem_Malloc(BUFSIZ); /* для ввода-вывода */131132if (buf == NULL)133    return PyErr_NoMemory();134/* ...Выполнить некоторые операции ввода-вывода с buf... */135res = PyString_FromString(buf);136PyMem_Free(buf); /* выделено с помощью PyMem_Malloc */137return res;138```139140Тот же код с использованием тип-ориентированного набора функций:141142```c143PyObject *res;144char *buf = PyMem_New(char, BUFSIZ); /* для ввода-вывода */145146if (buf == NULL)147    return PyErr_NoMemory();148/* ...Выполнить некоторые операции ввода-вывода с buf... */149res = PyString_FromString(buf);150PyMem_Del(buf); /* выделено с помощью PyMem_New */151return res;152```153154Обратите внимание, что в двух приведённых выше примерах буфер всегда обрабатывается с помощью функций из одного и того же набора. Действительно, для данного блока памяти необходимо использовать одно и то же семейство API для работы с памятью, чтобы риск смешивания разных аллокаторов был сведён к минимуму. Следующая последовательность кода содержит две ошибки, одна из которых помечена как *фатальная*, поскольку она смешивает два разных аллокатора, работающих с разными кучами.155156```c157char *buf1 = PyMem_New(char, BUFSIZ);158char *buf2 = (char *) malloc(BUFSIZ);159char *buf3 = (char *) PyMem_Malloc(BUFSIZ);160...161PyMem_Del(buf3);  /* Неверно -- следует использовать PyMem_Free() */162free(buf2);       /* Верно -- выделено через malloc() */163free(buf1);       /* Фатальная ошибка – следует использовать PyMem_Del()  */164```165166В дополнение к функциям, предназначенным для работы с сырыми блоками памяти из кучи Python, объекты в Python выделяются и освобождаются с помощью [`PyObject_New()`](https://python-all.ru/2.7/c-api/allocation.html#c.PyObject_New), [`PyObject_NewVar()`](https://python-all.ru/2.7/c-api/allocation.html#c.PyObject_NewVar) и [`PyObject_Del()`](https://python-all.ru/2.7/c-api/allocation.html#c.PyObject_Del).167168Они будут описаны в следующей главе, посвящённой определению и реализации новых типов объектов на C.169