Ответ
В CPython управление памятью автоматизировано с помощью двух основных механизмов: подсчёта ссылок и циклического сборщика мусора.
1. Подсчёт ссылок (Reference Counting)
Это основной и самый быстрый механизм. Каждый объект в Python имеет внутренний счётчик, который отслеживает количество ссылок на него.
- Когда на объект создается новая ссылка (например, присваивание переменной), его счётчик увеличивается.
- Когда ссылка удаляется (
del, выход из области видимости), счётчик уменьшается. - Как только счётчик достигает нуля, объект немедленно удаляется из памяти.
import sys
my_list = [1, 2, 3] # Создан объект, счетчик ссылок = 1
print(sys.getrefcount(my_list) - 1) # Вывод: 1
another_list = my_list # Новая ссылка, счетчик = 2
print(sys.getrefcount(my_list) - 1) # Вывод: 2
del another_list # Ссылка удалена, счетчик = 1
print(sys.getrefcount(my_list) - 1) # Вывод: 1
del my_list # Последняя ссылка удалена, счетчик = 0, объект удаляется
Проблема: Подсчёт ссылок не может обработать циклические ссылки, когда объекты ссылаются друг на друга, из-за чего их счётчики никогда не станут равны нулю, даже если они больше не доступны из программы.
2. Циклический сборщик (Generational GC)
Для решения проблемы циклических ссылок Python использует дополнительный алгоритм — сборщик мусора по поколениям.
- Принцип: Он основан на гипотезе, что большинство объектов "умирают молодыми". Поэтому все объекты разделены на три поколения (0, 1, 2).
- Процесс:
- Новые объекты попадают в поколение 0.
- Сборщик запускается чаще всего для самого молодого поколения.
- Он находит "недостижимые" объекты (включая циклические ссылки) с помощью алгоритма
mark-and-sweep(пометить и убрать). - Объекты, которые "выжили" после нескольких сборок в младшем поколении, перемещаются в старшее (из 0 в 1, из 1 в 2).
Управлять сборщиком можно с помощью модуля gc:
import gc
# Проверить, включен ли GC
print(gc.isenabled())
# Принудительно запустить сборку мусора
gc.collect() Ответ 18+ 🔞
А, слушай, про управление памятью в CPython, это вообще отдельная песня, ебать мои старые костыли! Там, в общем-то, два главных мудака за всё отвечают: подсчёт ссылок и циклический сборщик.
1. Подсчёт ссылок (Reference Counting)
Это главный пахан, быстрый, как хуй с горы. У каждого объекта в Python есть такой внутренний счётчик, который считает, сколько на него ссылок смотрит.
- Создал новую ссылку — счётчик плюсанул.
- Удалил ссылку (
delили просто переменная за scope вышла) — счётчик минусанул. - Как только счётчик в ноль ушёл — объект тут же, нахуй, в небытие отправляется. Мгновенно!
import sys
my_list = [1, 2, 3] # Создали объект, счётчик = 1
print(sys.getrefcount(my_list) - 1) # Вывод: 1
another_list = my_list # Новая ссылка, счётчик = 2
print(sys.getrefcount(my_list) - 1) # Вывод: 2
del another_list # Ссылку убили, счётчик = 1
print(sys.getrefcount(my_list) - 1) # Вывод: 1
del my_list # Последнюю ссылку прикончили, счётчик = 0, объект — пиздец.
Но проблема, сука, в чём: этот пахан не справляется с циклическими ссылками. Это когда два объекта друг на друга смотрят, как два мудака в зеркало, и их счётчики никогда в ноль не упадут, даже если программа про них уже забыла. Замкнутый круг, ёпта!
2. Циклический сборщик (Generational GC)
Вот для таких хитрожопых случаев есть второй мужик — сборщик мусора по поколениям. Он типа подчищает за первым.
- Идея простая: большинство объектов дохнут молодыми. Поэтому их всех поделили на три поколения (0, 1, 2).
- Как работает:
- Новый объект — сразу в поколение 0, на передовую.
- Сборщик чаще всего молодняк и проверяет, как салага.
- Ищет там недостижимое говно (включая эти ебучие циклические связи) по алгоритму «пометил и выкинул».
- Кто выжил после нескольких чисток в молодом поколении — того переводят в старшее (из 0 в 1, из 1 в 2). Как повышение, блядь.
Поковыряться в нём можно через модуль gc:
import gc
# Проверить, не выключили ли его случайно
print(gc.isenabled())
# Принудительно запустить уборку, если терпения ноль ебать ждать
gc.collect()
Вот так вот, в двух словах. Один работает быстро, но тупит на циклах, второй — медленнее, но подчищает за первым. Вместе — овердохуища работы делают, чтобы память не текла, как из дырявого ведра.