Поддержка циклической сборки мусора¶
Python поддерживает обнаружения и сборку мусора, которая включает в себя циклические ссылки, требует поддержки от типов объектов, которые являются «контейнерами» для других объектов, которые также могут быть контейнерами. Типы, которые не хранят ссылки на другие объекты или которые хранят ссылки только на атомарные типы (такие как числа или строки), не должны обеспечивать явную поддержку сбори мусора.
Для создания контейнерного типа поле tp_flags
объекта типа должно включать
Py_TPFLAGS_HAVE_GC
и обеспечивать реализацию tp_traverse
обработчик.
Если сущности типа являются изменяемыми, также должна быть предусмотрена tp_clear
реализация.
-
Py_TPFLAGS_HAVE_GC
Объекты с типом с таким набором флагов должны соответствовать правилам, описанным здесь. Для удобства эти объекты будут именоваться контейнерными объектами.
Конструкторы для типов контейнеров должны соответствовать двум правилам:
- Память объекта должна быть аллоцирована с помощью
PyObject_GC_New()
илиPyObject_GC_NewVar()
. - После инициализации всех полей, которые могут содержать ссылки на другие
контейнеры, необходимо вызвать
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
обработчик, станут действительными, как правило, ближе к концу конструктора.
Аналогично, деаллокатор для объекта должен соответствовать аналогичной паре правил:
- Перед признанием недействительными полей, ссылающихся на другие контейнеры,
необходимо вызвать
PyObject_GC_UnTrack()
. - Память объекта должна быть освобождена с помощью
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
обработчик становятся недействительными.
Изменено в версии 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
, если объект является неизменяемым.