Ответ
Счётчик ссылок (reference counting) — это основной механизм управления памятью в CPython. Его суть в том, что для каждого объекта в памяти хранится счётчик, который отслеживает, сколько переменных и структур данных на него ссылаются.
Принцип работы:
- Создание ссылки: Когда на объект создаётся новая ссылка (например, присваивание переменной), его счётчик увеличивается на 1.
- Удаление ссылки: Когда ссылка на объект удаляется (например, переменная выходит из области видимости или ей присваивается
None
), счётчик уменьшается на 1. - Освобождение памяти: Как только счётчик достигает нуля, это означает, что на объект больше нет ссылок, и сборщик мусора немедленно освобождает занимаемую им память.
Пример:
import sys
# 1. Создаем объект, на него ссылается 'a'. Счётчик = 1.
my_list = [1, 2, 3]
print(f"Ref count after creation: {sys.getrefcount(my_list)}")
# 2. Создаем новую ссылку 'b'. Счётчик = 2.
b = my_list
print(f"Ref count after new reference: {sys.getrefcount(my_list)}")
# 3. Удаляем ссылку 'b'. Счётчик = 1.
del b
print(f"Ref count after deleting one reference: {sys.getrefcount(my_list)}")
# Примечание: sys.getrefcount() сама создает временную ссылку,
# поэтому возвращаемое значение всегда на 1 больше реального.
Ограничения: циклические ссылки
Счётчик ссылок не может обработать циклические ссылки, когда два или более объектов ссылаются друг на друга. В этом случае их счётчики никогда не достигнут нуля, даже если на них нет внешних ссылок.
# a ссылается на b, а b ссылается на a
a = []
b = [a]
a.append(b)
# Даже после удаления внешних ссылок, они продолжают
# ссылаться друг на друга, и память не освобождается
del a
del b
Для решения этой проблемы в Python есть дополнительный механизм — поколенческий сборщик мусора (Generational Garbage Collector), который периодически находит и удаляет такие "осиротевшие" циклические группы объектов.