Perl использует алгоритм подсчёта ссылок для автоматического управления памятью: у каждой переменной есть счетчик ссылок. Когда счетчик становится равен нулю, память освобождается. В большинстве случаев это работает прозрачно — неиспользуемые переменные удаляются, как только выходят из области видимости.
Проблема возникает с циклическими ссылками (например, объект ссылается сам на себя или две структуры ссылаются друг на друга). В этом случае счетчик ссылок никогда не станет равен нулю, и память не освободится.
Для предотвращения утечек используется модуль Scalar::Util::weaken — позволяет создавать «ослабленные» ссылки, которые не увеличивают счетчик ссылок.
Пример:
use Scalar::Util qw(weaken); my $a = {}; my $b = { ref => $a }; $a->{ref} = $b; weaken($a->{ref}); # теперь нет циклической сильной зависимости
Правильно ли полагать, что Perl всегда автоматически освобождает всю неиспользуемую память, даже при наличии сложных взаимосвязанных структур?
Ответ и пример:
Нет! В случае циклических ссылок Perl не сможет освободить память автоматически, если не использовать weaken:
my $a = {}; $a->{self} = $a; # цикл # $a никогда не удалится автоматически — потребуется ручной разрыв или ослабление ссылки
История 1: На большом Perl web-сервисе был memory leak — сессии пользователей хранили ссылки друг на друга в хэше, и никто не использовал ослабленные ссылки. Сервис за сутки расходовал все ресурсы, зависал и требовал рестартов.
История 2: Самописный ORM создавал циклы между объектами User и Group, каждый из которых ссылался на друг друга. После выхода из области видимости объекты оставались в памяти — сервис постепенно "разбухал" до десятков гигабайт!
История 3: Использование анонимных подпрограмм («закрытий») в качестве методов класса, ссылающихся на
$self, приводило к утечкам при каждом создании объекта, пока не появился анализатор, выявивший циклические ссылки и указавший на необходимостьweaken.