Поддержка циклической сборки мусора¶Supporting Cyclic Garbage Collection
Для поддержки обнаружения и сбора мусора, связанного с циклическими ссылками, Python требует поддержки от типов объектов, которые являются «контейнерами» для других объектов (которые также могут быть контейнерами). Типы, не хранящие ссылок на другие объекты или хранящие ссылки только на атомарные типы (например, числа или строки), не нуждаются в явной поддержке сборки мусора.
Чтобы создать контейнерный тип, поле tp_flags объекта типа должно содержать флаг Py_TPFLAGS_HAVE_GC, а также нужно предоставить реализацию обработчика tp_traverse. Если экземпляры типа изменяемы, необходимо также реализовать tp_clear.
- Py_TPFLAGS_HAVE_GC
- Объекты с типом, у которого установлен этот флаг, должны соответствовать описанным здесь правилам. Для удобства такие объекты будут называться контейнерными объектами.
Конструкторы контейнерных типов должны соответствовать двум правилам:
- Память для объекта должна выделяться с помощью PyObject_GC_New или PyObject_GC_VarNew.
- После инициализации всех полей, которые могут содержать ссылки на другие контейнеры, необходимо вызвать 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.
- PyVarObject * PyObject_GC_Resize(PyVarObject *op, Py_ssize_t)¶
- Изменяет размер объекта, выделенного с помощью PyObject_NewVar. Возвращает объект нового размера или NULL в случае ошибки.
- void PyObject_GC_Track(PyObject *op)¶
- Добавляет объект op в набор контейнерных объектов, отслеживаемых сборщиком. Сборщик может запускаться в неожиданные моменты, поэтому объекты должны быть корректными на время отслеживания. Этот вызов следует выполнить, когда все поля, обрабатываемые обработчиком tp_traverse, станут корректными, обычно ближе к концу конструктора.
- void _PyObject_GC_TRACK(PyObject *op)¶
- Макроверсия PyObject_GC_Track. Не предназначена для использования в модулях расширения.
Аналогично, деаллокатор объекта должен соответствовать такой же паре правил:
- Перед тем, как поля, ссылающиеся на другие контейнеры, станут недействительными, необходимо вызвать 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, станет недействительным.
- void _PyObject_GC_UNTRACK(PyObject *op)¶
- Макроверсия PyObject_GC_UnTrack. Не предназначена для использования в модулях расширения.
Обработчик 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)¶
Вызывает колбэк 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; }
The tp_clear handler must be of the inquiry type, or NULL if the object is immutable.
- int (*inquiry)(PyObject *self)¶
- Удаляет ссылки, которые могли создать циклические ссылки. Неизменяемые объекты могут не определять этот метод, так как они никогда не могут напрямую создавать циклические ссылки. Обратите внимание, что объект после вызова этого метода всё ещё должен оставаться корректным (не следует просто вызывать Py_DECREF для ссылки). Сборщик вызовет этот метод, если обнаружит, что этот объект участвует в циклической ссылке.