Spec-Zone.ru › Python 3.8

Поддержка обнаружения циклов в сборщике мусора

Поддержка Python для обнаружения и сбора мусора, связанного с циклическими ссылками, требует поддержки типов объектов, являющихся «контейнерами» для других объектов, которые также могут быть контейнерами. Типы, которые не хранят ссылки на другие объекты или которые хранят только ссылки на атомарные типы (такие как числа или строки), не нуждаются в предоставлении явной поддержки для сборки мусора.

Для создания контейнерного типа поле tp_flags объекта типа должно включать Py_TPFLAGS_HAVE_GC и предоставить реализацию обработчика tp_traverse. Если экземпляры типа изменяемы, также должна быть предоставлена реализация tp_clear.

Py_TPFLAGS_HAVE_GC

Объекты с типом, для которого установлен этот флаг, должны соответствовать правилам, описанным здесь. Для удобства эти объекты будут называться контейнерными объектами.

Конструкторы контейнерных типов должны соответствовать двум правилам:

  1. Память для объекта должна быть выделена с помощью PyObject_GC_New() или PyObject_GC_NewVar().
  2. После инициализации всех полей, которые могут содержать ссылки на другие контейнеры, необходимо вызвать PyObject_GC_Track().
TYPE* PyObject_GC_New(TYPE, PyTypeObject *type)

Аналогично PyObject_New(), но для контейнерных объектов, для которых установлен флаг Py_TPFLAGS_HAVE_GC.

TYPE* PyObject_GC_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size)

Аналогично PyObject_NewVar(), но для контейнерных объектов, для которых установлен флаг Py_TPFLAGS_HAVE_GC.

TYPE* PyObject_GC_Resize(TYPE, PyVarObject *op, Py_ssize_t newsize)

Изменение размера объекта, выделенного с помощью PyObject_NewVar(). Возвращает измененный объект или NULL при ошибке. op пока не должен отслеживаться сборщиком.

void PyObject_GC_Track(PyObject *op)

Добавляет объект op в множество контейнерных объектов, отслеживаемых сборщиком. Сборщик может выполняться в непредвиденное время, поэтому объекты должны быть валидными во время отслеживания. Это должно быть вызвано после того, как все поля, за которыми следует обработчик tp_traverse станут валидными, обычно в конце конструктора.

Аналогично, деаллокатору объекта должны соответствовать похожие пары правил:

  1. Перед тем, как поля, ссылающиеся на другие контейнеры, будут аннулированы, необходимо вызвать PyObject_GC_UnTrack().
  2. Память объекта должна быть освобождена с помощью PyObject_GC_Del().
void PyObject_GC_Del(void *op)

Освобождает память, выделенную для объекта с помощью PyObject_GC_New() или PyObject_GC_NewVar().

void PyObject_GC_UnTrack(void *op)

Удаляет объект op из набора контейнерных объектов, отслеживаемых сборщиком. Обратите внимание, что PyObject_GC_Track() может быть вызван снова для этого объекта, чтобы добавить его обратно в набор отслеживаемых объектов. Деаллокатору (tp_dealloc handler) следует вызвать это для объекта перед тем, как какие-либо поля, используемые обработчиком tp_traverse, станут недействительными.

Изменено в версии 3.8: Макросы _PyObject_GC_TRACK() и _PyObject_GC_UNTRACK() были удалены из публичного C API.

Обработчик tp_traverse принимает в качестве параметра функцию этого типа:

int (*visitproc)(PyObject *object, void *arg)

Тип функции-визитора, передаваемой обработчику tp_traverse. Функция должна вызываться с объектом для обхода в качестве object и третьим параметром обработчика tp_traverse в качестве arg. Ядро Python использует несколько функций-визиторов для реализации обнаружения циклов в сборке мусора; не ожидается, что пользователям потребуется писать собственные функции-визиторы.

Обработчик tp_traverse должен иметь следующий тип:

int (*traverseproc)(PyObject *self, visitproc visit, void *arg)

Функция обхода для контейнерного объекта. Реализации должны вызывать функцию visit для каждого объекта, непосредственно содержащегося объектом self, при этом параметрами visit являются содержащийся объект и значение arg, переданное обработчику. Функция visit не должна вызываться с объектом-аргументом NULL. Если visit возвращает ненулевое значение, это значение должно быть возвращено немедленно.

Для упрощения написания обработчиков tp_traverse, предоставляется макрос Py_VISIT(). Для использования этого макроса, реализация tp_traverse должна точно называть свои аргументы visit и arg:

void Py_VISIT(PyObject *o)

Если o не NULL, вызовите обратный вызов visit с аргументами o и arg. Если visit возвращает ненулевое значение, верните его. Используя этот макрос, обработчики tp_traverse выглядят следующим образом:

static int
my_traverse(Noddy *self, visitproc visit, void *arg)
{
    Py_VISIT(self->foo);
    Py_VISIT(self->bar);
    return 0;
}

Обработчик tp_clear должен быть типа inquiry, или NULL если объект неизменяемый.

int (*inquiry)(PyObject *self)

Удаление ссылок, которые могут создать циклы ссылок. Неизменяемые объекты не обязаны определять этот метод, так как они никогда не могут напрямую создавать циклы ссылок. Обратите внимание, что объект должен оставаться валидным после вызова этого метода (не нужно просто вызывать Py_DECREF() для ссылки). Сборщик вызовет этот метод, если обнаружит, что этот объект участвует в цикле ссылок.

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/c-api/gcsupport.html

Spec-Zone.ru

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