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

Поддержка циклической сборки мусораSupporting Cyclic Garbage Collection

Поддержка 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, станут корректны, обычно ближе к концу конструктора.

void _PyObject_GC_TRACK(PyObject *op)

Макроверсия PyObject_GC_Track(). Не следует использовать для модулей расширения.

Устарело с версии 3.6: Этот макрос удалён из Python 3.8.

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

  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) должен вызывать это для объекта до того, как какие-либо поля, используемые обработчиком tp_traverse, станут недействительными.

void _PyObject_GC_UNTRACK(PyObject *op)

Макроверсия PyObject_GC_UnTrack(). Не следует использовать для модулей расширения.

Устарело с версии 3.6: Этот макрос удалён из Python 3.8.

Обработчик 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() для ссылки). Сборщик вызовет этот метод, если обнаружит, что этот объект участвует в циклической ссылке.