> **Источник:** https://python-all.ru/3.0/c-api/gcsupport.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# Поддержка циклической сборки мусора

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

Чтобы создать контейнерный тип, поле [`tp_flags`](https://python-all.ru/3.0/c-api/typeobj.html#tp_flags) объекта типа должно содержать флаг [`Py_TPFLAGS_HAVE_GC`](https://python-all.ru/3.0/c-api/typeobj.html#Py_TPFLAGS_HAVE_GC), а также нужно предоставить реализацию обработчика [`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse). Если экземпляры типа изменяемы, необходимо также реализовать [`tp_clear`](https://python-all.ru/3.0/c-api/typeobj.html#tp_clear).

#### `Py_TPFLAGS_HAVE_GC`

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

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

1. Память для объекта должна выделяться с помощью [`PyObject_GC_New`](https://python-all.ru/3.0/c-api/gcsupport.html#PyObject_GC_New) или `PyObject_GC_VarNew`.
2. После инициализации всех полей, которые могут содержать ссылки на другие контейнеры, необходимо вызвать [`PyObject_GC_Track`](https://python-all.ru/3.0/c-api/gcsupport.html#PyObject_GC_Track).

**\[PyObject\_GC\_New\]TYPE\* `PyObject_GC_New`(TYPE, [PyTypeObject](https://python-all.ru/3.0/c-api/type.html#PyTypeObject) *\*type*)**

Аналог

[`PyObject_New`](https://python-all.ru/3.0/c-api/allocation.html#PyObject_New)

, но для контейнерных объектов с установленным флагом

[`Py_TPFLAGS_HAVE_GC`](https://python-all.ru/3.0/c-api/typeobj.html#Py_TPFLAGS_HAVE_GC)

.

**\[PyObject\_GC\_NewVar\]TYPE\* `PyObject_GC_NewVar`(TYPE, [PyTypeObject](https://python-all.ru/3.0/c-api/type.html#PyTypeObject) *\*type*, Py\_ssize\_t *size*)**

Аналог

[`PyObject_NewVar`](https://python-all.ru/3.0/c-api/allocation.html#PyObject_NewVar)

, но для контейнерных объектов с установленным флагом

[`Py_TPFLAGS_HAVE_GC`](https://python-all.ru/3.0/c-api/typeobj.html#Py_TPFLAGS_HAVE_GC)

.

**\[PyObject\_GC\_Resize\][PyVarObject](https://python-all.ru/3.0/c-api/structures.html#PyVarObject) \* `PyObject_GC_Resize`([PyVarObject](https://python-all.ru/3.0/c-api/structures.html#PyVarObject) *\*op*, Py\_ssize\_t)**

Изменяет размер объекта, выделенного с помощью

[`PyObject_NewVar`](https://python-all.ru/3.0/c-api/allocation.html#PyObject_NewVar)

. Возвращает объект нового размера или

*NULL*

в случае ошибки.

**\[PyObject\_GC\_Track\]void `PyObject_GC_Track`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*op*)**

Добавляет объект

*op*

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

[`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse)

, станут корректными, обычно ближе к концу конструктора.

**\[\_PyObject\_GC\_TRACK\]void `_PyObject_GC_TRACK`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*op*)**

Макроверсия

[`PyObject_GC_Track`](https://python-all.ru/3.0/c-api/gcsupport.html#PyObject_GC_Track)

. Не предназначена для использования в модулях расширения.

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

1. Перед тем, как поля, ссылающиеся на другие контейнеры, станут недействительными, необходимо вызвать [`PyObject_GC_UnTrack`](https://python-all.ru/3.0/c-api/gcsupport.html#PyObject_GC_UnTrack).
2. Память объекта должна освобождаться с помощью [`PyObject_GC_Del`](https://python-all.ru/3.0/c-api/gcsupport.html#PyObject_GC_Del).

**\[PyObject\_GC\_Del\]void `PyObject_GC_Del`(void *\*op*)**

Освобождает память, выделенную для объекта с помощью

[`PyObject_GC_New`](https://python-all.ru/3.0/c-api/gcsupport.html#PyObject_GC_New)

или

[`PyObject_GC_NewVar`](https://python-all.ru/3.0/c-api/gcsupport.html#PyObject_GC_NewVar)

.

**\[PyObject\_GC\_UnTrack\]void `PyObject_GC_UnTrack`(void *\*op*)**

Удаляет объект

*op*

из набора контейнерных объектов, отслеживаемых сборщиком. Обратите внимание, что для этого объекта можно снова вызвать

[`PyObject_GC_Track`](https://python-all.ru/3.0/c-api/gcsupport.html#PyObject_GC_Track)

, чтобы вернуть его в набор отслеживаемых объектов. Деаллокатор (обработчик

[`tp_dealloc`](https://python-all.ru/3.0/c-api/typeobj.html#tp_dealloc)

) должен вызвать это для объекта до того, как любое из полей, используемых обработчиком

[`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse)

, станет недействительным.

**\[\_PyObject\_GC\_UNTRACK\]void `_PyObject_GC_UNTRACK`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*op*)**

Макроверсия

[`PyObject_GC_UnTrack`](https://python-all.ru/3.0/c-api/gcsupport.html#PyObject_GC_UnTrack)

. Не предназначена для использования в модулях расширения.

Обработчик [`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse) принимает параметр-функцию следующего типа:

**\[visitproc\]int `(*visitproc)`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*object*, void *\*arg*)**

Тип функции посетителя, передаваемой обработчику

[`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse)

. Функция должна вызываться с объектом для обхода в качестве

*object*

и третьим параметром обработчика

[`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse)

в качестве

*arg*

. Ядро Python использует несколько функций посетителей для реализации обнаружения циклического мусора; не ожидается, что пользователям потребуется писать собственные функции посетителей.

Обработчик [`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse) должен иметь следующий тип:

**\[traverseproc\]int `(*traverseproc)`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*self*, [visitproc](https://python-all.ru/3.0/c-api/gcsupport.html#visitproc) *visit*, void *\*arg*)**

Функция обхода для контейнерного объекта. Реализации должны вызывать функцию

*visit*

для каждого объекта, напрямую содержащегося в

*self*

, с параметрами для

*visit*

: содержащимся объектом и значением

*arg*

, переданным обработчику. Функция

*visit*

не должна вызываться с аргументом

*NULL*

в качестве объекта. Если

*visit*

возвращает ненулевое значение, его следует немедленно вернуть.

Для упрощения написания обработчиков [`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse) предоставляется макрос [`Py_VISIT`](https://python-all.ru/3.0/c-api/gcsupport.html#Py_VISIT). Чтобы использовать этот макрос, реализация [`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse) должна называть свои аргументы именно *visit* и *arg*:

**\[Py\_VISIT\]void `Py_VISIT`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*o*)**

Вызывает колбэк *visit* с аргументами *o* и *arg*. Если *visit* возвращает ненулевое значение, вернуть его. Используя этот макрос, обработчики [`tp_traverse`](https://python-all.ru/3.0/c-api/typeobj.html#tp_traverse) выглядят так:

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

The [`tp_clear`](https://python-all.ru/3.0/c-api/typeobj.html#tp_clear) handler must be of the [`inquiry`](https://python-all.ru/3.0/c-api/gcsupport.html#inquiry) type, or *NULL* if the object is immutable.

**\[inquiry\]int `(*inquiry)`([PyObject](https://python-all.ru/3.0/c-api/structures.html#PyObject) *\*self*)**

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

[`Py_DECREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_DECREF)

для ссылки). Сборщик вызовет этот метод, если обнаружит, что этот объект участвует в циклической ссылке.
