В Perl память под переменные и структуры данных управляется с помощью механизма подсчета ссылок (reference counting). Объект или структура освобождается, когда счетчик ссылок опускается до нуля.
Однако этот механизм НЕ расследует циклические ссылки. Если объекты ссылаются друг на друга, их счетчики не достигают нуля, и память не освобождается.
Для очистки циклических ссылок используют:
Scalar::Util::weaken. Слабая ссылка не увеличивает счетчик ссылок, позволяя GC освободить объект, если других сильных ссылок нет.Пример создания слабой ссылки:
use Scalar::Util 'weaken'; my $parent = {}; my $child = { parent => $parent }; $parent->{child} = $child; weaken($child->{parent}); # теперь parent->child->parent не мешает очистке
Может ли Perl сам "распознать" и освободить циклические ссылки без модуля Scalar::Util или ручного вмешательства?
Нет, Perl по умолчанию не умеет автоматически "собирать" циклические структуры, поскольку этот механизм требует анализа структуры графа объектов (как, например, GC в JVM или Python). Так что всегда нужно заботиться об очистке циклов самостоятельно.
История
В сервере хранения сессий для веб-приложения активно использовались объекты User с двусторонними связями. Оказалось, что после нескольких тысяч обращений память процесса росла из-за циклов: $user->{session}->{user} = $user. Утечка исчезла после введения weaken для обратных ссылок.
История
При использовании кэша с LRU-алгоритмом хранили цепочки объектов друг на друга через ссылки. Разработчики не предусмотрели ручного обнуления связей, что привело к резкому росту памяти после нескольких дней работы сервиса и краху от OOM.
История
В сложном микросервисе для хранения документов при генерации отчетов использовали eval и крупномасштабные структуры данных с циклическими ссылками. Разработчики рассчитывали на автоматическую сборку мусора Perl, но сервер "запоминал" старые объекты и через неделю работы утратил всю доступную RAM. Диагностика выявила циклы и использовала Scalar::Util после каждого отчета.