Удалится ли циклическая структура из памяти и когда это происходит в Python?
Что проверяют
Знаете ли вы, что в CPython два разных механизма освобождения памяти, и понимаете ли, какой из них разбирает циклы и когда он срабатывает. В работе с данными это не теория: цикл, удерживающий большой массив или модель, держит и всю занятую ими память.
Как отвечать
Удалится, но не сразу. Счётчик ссылок тут бессилен: объекты в цикле ссылаются друг на друга, счётчики не доходят до нуля, и удаление имени ничего не освобождает.
Такие объекты забирает отдельный сборщик циклов. Он поколенческий, поколений три, и запускается не по таймеру, а когда разница между числом созданных и уничтоженных контейнеров превышает порог поколения. Ищет он не достижимость от корней: сборщик пробно вычитает ссылки, идущие изнутри группы объектов, и если после этого счётчик обнулился, группа недостижима снаружи и подлежит удалению.
import gc
class Node: pass
a, b = Node(), Node()
a.ref, b.ref = b, a
del a, b # память ещё занята
gc.collect() # теперь освобожденаПолезные детали: сборщик следит только за контейнерами, числа и строки в циклы попасть не могут; ручной gc.collect уместен после освобождения крупных структур; разорвать цикл заранее помогает слабая ссылка через weakref.
Где спотыкаются
Говорят, что циклические ссылки в Python текут навсегда. Это верно для наивного подсчёта ссылок и было правдой для объектов с __del__ в очень старых версиях, но сейчас такие циклы собираются штатно.
Вторая ошибка: считать del освобождением памяти. Инструкция убирает имя и уменьшает счётчик, а память возвращается только при обнулении счётчика или при проходе сборщика циклов.
Третья важна именно в задачах с данными: сборка запускается по счётчику выделений контейнеров, а не по занятому объёму. Скрипт может держать гигабайты в паре объектов и не создавать новых, тогда порог не сработает. Поэтому после удаления тяжёлых структур сборку зовут руками.