0Pricing
Python Academy · Урок

Сборщик мусора и циклические ссылки

Узнайте, как модуль gc обрабатывает циклы ссылок.

«Сборщик мусора и циклические ссылки» — бесплатный урок Python Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Python Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Python Academy содержит 4 уроков всего.

Почему подсчёта ссылок недостаточно

Подсчёт ссылок не может собрать объекты, участвующие в циклах ссылок: каждый объект хранит ссылку на другой, поэтому ни один счётчик не уменьшается до 0.

# Reference cycle: a → b → a
a = {}
b = {"other": a}
a["other"] = b
del a, b
# Both objects are unreachable but refcount > 0
# Only the cyclic GC can collect them

Модуль gc

gc — это циклический сборщик мусора. Он периодически сканирует отслеживаемые объекты, находя недоступные циклы, и собирает их.

import gc

gc.collect()   # trigger immediately
print(gc.garbage)   # objects with __del__ in cycles (cannot auto-collect)

Поколенческий сбор

Сборщик мусора использует три поколения. Новые объекты начинают с поколения 0. Объекты, пережившие сборку, переводятся в следующее поколение. Поколение 0 собирается чаще всего.

import gc

print(gc.get_count())     # (gen0, gen1, gen2) allocations since last collection
print(gc.get_threshold()) # (700, 10, 10) — thresholds for each generation
gc.set_threshold(1000, 15, 10)  # tune

Обнаружение циклов с помощью gc.get_referents

Проверяйте, на какие объекты ссылается объект: это полезно для понимания того, почему что-то не собирается.

import gc

a = []
b = [a]
a.append(b)

for ref in gc.get_referents(a):
    print(ref)   # shows b

gc.get_objects()

gc.get_objects() возвращает все объекты, которые в данный момент отслеживаются сборщиком мусора. Это полезно для поиска утечек памяти.

import gc

before = len(gc.get_objects())
create_lots_of_objects()
after = len(gc.get_objects())
print(f"Leaked: {after - before} objects")

Предотвращение циклов

Проектируйте структуры данных так, чтобы избегать циклов: используйте слабые ссылки для обратных ссылок, идентификаторы вместо прямых ссылок или явно разрывайте циклы до выхода объектов из области видимости.

import weakref

class Node:
    def __init__(self, parent):
        # weakref avoids cycle:
        self.parent = weakref.ref(parent)

class Tree:
    def __init__(self):
        self.child = Node(self)   # no hard cycle

__del__ и циклы

Объекты с __del__, участвующие в цикле, не могут быть автоматически собраны. Вместо этого они помещаются в gc.garbage.

import gc

class Leaky:
    def __del__(self): pass

a = Leaky()
b = Leaky()
a.other = b
b.other = a
del a, b

gc.collect()
print(gc.garbage)   # [Leaky, Leaky] — cannot collect

gc.freeze() — Python 3.7+

gc.freeze() замораживает отслеживаемые в данный момент объекты, поэтому они больше никогда не собираются. Это полезно в долгоживущих процессах после запуска, чтобы уменьшить паузы сборщика мусора.

import gc

# After all globals and imports are in place:
gc.freeze()   # no GC scanning for these objects ever again

# Useful for: gunicorn pre-fork, background servers

Отключение и повторное включение сборщика мусора

Отключайте циклический сборщик мусора в плотных циклах, где Вы уверены в отсутствии циклов, а затем снова включайте его и принудительно запускайте сборку.

import gc

gc.disable()
try:
    result = tight_loop_no_cycles()
finally:
    gc.enable()
    gc.collect()

isenabled и isfinalized

Проверяйте состояние сборщика мусора с помощью gc.isenabled() и определяйте, завершается ли обработка объекта, с помощью gc.is_finalized(obj).

import gc

print(gc.isenabled())      # True by default
obj = object()
print(gc.is_finalized(obj))  # False (still alive)

Типичные причины утечек памяти

Распространённые причины утечек памяти в Python: глобальные кэши, бесконтрольно увеличивающиеся в размере, неотсоединённые обработчики событий, циклические ссылки с __del__ и расширения на C, из которых утекают ссылки.

# Typical leaks:
global_cache = {}   # grows forever — use lru_cache with maxsize

class EventBus:
    listeners = []
    # Listeners hold references to objects:
    # @classmethod
    # def on(cls, fn): cls.listeners.append(fn)
    # Must call off() to detach

Быстрая проверка

Что происходит с объектами, имеющими __del__ и участвующими в цикле ссылок?

Итоги

Циклический сборщик мусора обрабатывает циклы ссылок, с которыми не справляется подсчёт ссылок. Он использует три поколения и переводит выжившие объекты в следующие поколения. Избегайте циклов с помощью слабых ссылок. Объекты с __del__ в циклах попадают в gc.garbage. Используйте gc.freeze() после запуска, чтобы уменьшить паузы сборщика мусора в долгоживущих серверах.

Часто задаваемые вопросы

Урок «Сборщик мусора и циклические ссылки» бесплатный?

Да — полный текст урока «Сборщик мусора и циклические ссылки» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Python Academy, подпишись на CoddyKit PRO. Курс Python Academy содержит 4 уроков всего.

Чему я научусь в уроке «Сборщик мусора и циклические ссылки»?

Узнайте, как модуль gc обрабатывает циклы ссылок. Ты практикуешь Python Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Python Academy?

Предыдущий опыт не требуется. Python Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Сборщик мусора и циклические ссылки»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Python Academy?

Да. Каждый урок Python Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Подсчёт ссылок в CPython
  2. Сборщик мусора и циклические ссылки
  3. Профилирование с cProfile и line_profiler
  4. Профилирование памяти с tracemalloc
← Назад к Python Academy