Как работает сборщик мусора (Garbage Collector) в Python?

Ответ

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

Основной механизм (подсчет ссылок):

  • Каждый объект имеет счетчик ссылок.
  • При создании новой ссылки счетчик увеличивается, при удалении — уменьшается.
  • Когда счетчик достигает нуля, память объекта немедленно освобождается.

Циклический сборщик (Generational GC):

  • Обнаруживает и удаляет циклические ссылки (когда объекты ссылаются друг на друга, но недоступны извне).
  • Использует поколения (0, 1, 2). Новые объекты попадают в поколение 0.
  • Чаще проверяет молодые поколения, реже — старые.

Пример цикла:

class Node:
    def __init__(self):
        self.ref = None

# Создание циклической ссылки
a = Node()
b = Node()
a.ref = b
b.ref = a
# Удаляем внешние ссылки
a = None
b = None
# Теперь объекты недостижимы, но счетчики ссылок не нулевые.
# Их удалит циклический сборщик.

Управление GC:

  • gc.enable() / gc.disable() — включить/выключить.
  • gc.collect() — принудительный запуск.
  • gc.get_threshold() — пороги для поколений.

Ответ 18+ 🔞

Да ты посмотри, какая красота, блядь! В Питоне-то, оказывается, мусор выносят по-умному, а не как у нас в подъезде. Сидит себе тихо сборщик на подсчёте ссылок, как бухгалтер в конторе.

Вот как он, сука, работает (основной механизм):

  • У каждого объекта, будь то список, словарь или твоя кривая функция, есть свой личный счётчик, блядь.
  • Как только на него кто-то начинает показывать пальцем (создаётся ссылка) — счётчик плюсует. Отвёл взгляд (удалил ссылку) — минусует.
  • И вот когда этот счётчик падает до нуля — тут же, нахуй, объект в утиль! Память чиста. Красота, ёпта.

Но есть же, блядь, и подлянка — циклические ссылки! Вот тут вступает циклический сборщик (Generational GC), этакий спецназ по зачистке говна.

  • Его задача — находить эти вот пиздецовые круговые поручительства, когда два объекта друг за друга держатся, но весь остальной мир про них уже забыл. Мёртвый хват, блядь.
  • Работает он по поколениям (0, 1, 2). Всё новое и горячее — в поколение 0, как молодые пиздюки. Их проверяют часто-часто. А то, что выжило после нескольких чисток, переходит в поколения постарше, и их уже тревожат реже. Логично же, ебать мои старые костыли.

Смотри, какой наглядный пиздец:

class Node:
    def __init__(self):
        self.ref = None

# Создаём циклическую ссылку — классика жанра!
a = Node()
b = Node()
a.ref = b
b.ref = a  # Всё, они поженились, блядь.
# А теперь внешний мир о них забывает
a = None
b = None
# И сидят теперь два этих чудака, держатся за ручки, счётчики у них по 1, но они уже никому не нужны!
# Вот тут наш циклический сборщик и придёт, как санитар леса, и разъебёт этот порочный круг.

Ну и если совсем припёрло, можно им порулить:

  • gc.enable() / gc.disable() — включить или вырубить этого санитара нахуй.
  • gc.collect() — орать на него "Давай, работай, блядь, сейчас же!" для принудительной зачистки.
  • gc.get_threshold() — посмотреть, через сколько пинков он начинает проверять каждое поколение.