Поддержка циклического сбора мусора
Поддержка Python для обнаружения и сбора мусора, включающего циклические ссылки, требует поддержки от типов объектов, которые являются «контейнерами» для других объектов, которые также могут быть контейнерами. Типы, которые не хранят ссылки на другие объекты или которые хранят ссылки только на атомарные типы (такие как числа или строки), не нуждаются в предоставлении явной поддержки для сбора мусора.
Для создания контейнерного типа поле tp_flags объекта типа должно включать Py_TPFLAGS_HAVE_GC и предоставить реализацию обработчика tp_traverse. Если экземпляры типа изменяемые, необходимо также предоставить реализацию tp_clear.
-
Py_TPFLAGS_HAVE_GC -
Объекты с типом, для которого установлен этот флаг, должны соответствовать правилам, описанным здесь. Для удобства эти объекты будут называться контейнерными объектами.
Конструкторы для контейнерных типов должны соответствовать двум правилам:
- Память для объекта должна быть выделена с использованием
PyObject_GC_New()илиPyObject_GC_NewVar(). - После инициализации всех полей, которые могут содержать ссылки на другие контейнеры, необходимо вызвать
PyObject_GC_Track().
Аналогично, обработчик освобождения памяти объекта должен соответствовать аналогичной паре правил:
- Перед тем, как поля, которые ссылаются на другие контейнеры, будут аннулированы, необходимо вызвать
PyObject_GC_UnTrack(). -
Память объекта должна быть освобождена с использованием
PyObject_GC_Del().Предупреждение
Если тип добавляет Py_TPFLAGS_HAVE_GC, то он обязательно должен реализовать по крайней мере обработчик
tp_traverseили явно использовать один из своих подклассов или подклассов.При вызове
PyType_Ready()или некоторых API, которые косвенно вызывают его, таких какPyType_FromSpecWithBases()илиPyType_FromSpec(), интерпретатор автоматически заполнит поляtp_flags,tp_traverseиtp_clear, если тип унаследован от класса, который реализует протокол сборщика мусора, и дочерний класс не включает флагPy_TPFLAGS_HAVE_GC.
-
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, станут валидными, обычно в конце конструктора.
-
int PyObject_IS_GC(PyObject *obj) -
Возвращает ненулевое значение, если объект реализует протокол сборщика мусора, в противном случае возвращает 0.
Объект не может быть отслеживаем сборщиком мусора, если эта функция возвращает 0.
-
int PyObject_GC_IsTracked(PyObject *op) -
Возвращает 1, если тип объекта op реализует протокол GC и op в настоящее время отслеживается сборщиком мусора, и 0 в противном случае.
Это аналогично функции Python
gc.is_tracked().Новое в версии 3.9.
-
int PyObject_GC_IsFinalized(PyObject *op) -
Возвращает 1, если тип объекта op реализует протокол GC и op уже был завершен сборщиком мусора, и 0 в противном случае.
Это аналогично функции Python
gc.is_finalized().Новое в версии 3.9.
-
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 если объект неизменяемый.
-
int (*inquiry)(PyObject *self) -
Удалите ссылки, которые могли создать циклы ссылок. Неизменяемые объекты не обязаны определять этот метод, поскольку они никогда не могут напрямую создавать циклы ссылок. Обратите внимание, что объект должен оставаться валидным после вызова этого метода (не просто вызывайте
Py_DECREF()для ссылки). Сборщик мусора вызовет этот метод, если обнаружит, что этот объект участвует в цикле ссылок.
© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/c-api/gcsupport.html