Короткий ответ
Основной механизм в CPython — подсчёт ссылок: объект удаляется сразу, когда счётчик ссылок падает до нуля; дополнительный циклический сборщик мусора периодически удаляет группы объектов, ссылающихся друг на друга циклически, которые иначе никогда не достигнут нулевого refcount.
Как это работает подробнее
Каждый объект хранит счётчик ссылок; создание новой ссылки увеличивает его, удаление переменной — уменьшает. При достижении нуля объект освобождается немедленно. Для циклических ссылок (A ссылается на B, B — на A) счётчик никогда не упадёт до нуля сам по себе — этим занимается модуль gc.
Пример кода
example-259.py
import sys, gc
class Node:
def __init__(self):
self.ref = None
x, y = Node(), Node()
x.ref, y.ref = y, x # цикл: x -> y -> x
del x, y
# Объекты не освобождены по refcount (цикл), но будут найдены циклическим gc
collected = gc.collect()
print(collected) # покажет количество собранных объектов > 0Что использовать на практике
- Практика. Для большинства кода управление памятью прозрачно; явный
gc.collect()иногда вызывают в тестах или после операций, создающих много временных циклических структур, чтобы детерминированно освободить память перед замером.
Подводные камни
- Риски. Считают, что
del objвсегда немедленно освобождает память, забывая про циклы; либо расставляютgc.collect()повсеместно «на всякий случай», что снижает производительность без улучшения корректности.