Исторически Perl поддерживает лексическую область видимости переменных, что позволяет использовать замыкания (closures) — функции, сохраняющие внешнее окружение. Проблема возникает, когда замыкание ссылается на переменные вне своей области видимости или когда вложенные структуры создают циклические ссылки, что приводит к утечкам памяти из‑за неаккуратного обращения с ссылками.
Решение — использовать замыкания для создания фабрик функций и функционального стиля, и при этом помнить о правильном управлении ссылками при замыкании переменных из внешнего scope.
Пример кода:
sub make_counter { my $count = 0; return sub { $count++; }; } my $counter = make_counter(); print $counter->(), " "; # 0 print $counter->(), " "; # 1
Ключевые особенности:
Что будет, если вернуть анонимную функцию ссылающуюся на саму себя?
Будет создана циклическая ссылка, которую Perl не сможет автоматически собрать сборщиком мусора. Это приведет к утечке памяти. Для решения используйте слабые ссылки, модуль Scalar::Util:
use Scalar::Util qw(weaken); my $foo; $foo = sub { ... $foo ... }; weaken($foo);
Всегда ли замыкание захватывает «копию» переменной, или это ссылка на ту же самую переменную?
Замыкание всегда оперирует текущей переменной, её область видимости фиксируется при создании closure. Таким образом, переменная одна и та же для всех вызовов функции closure.
Можно ли сделать так, чтобы замыкание работало с изменяемым состоянием вне себя, но не держало на него жёсткую ссылку?
Да, используйте слабые ссылки (Scalar::Util::weaken) или структурируйте код, чтобы ссылки были удерживаются только там, где это нужно (например, передавайте данные извне при каждом вызове closure).
Создали callback‑closure, которое замыкает $self из OO‑объекта, и держится внутри хэша callbacks. После уничтожения объекта память не освобождается.
Плюсы:
Минусы:
Closure корректно слабо ссылается на $self с помощью Scalar::Util::weaken:
use Scalar::Util qw(weaken); my $cb = sub { my $self = shift; weaken($self); ... };
Плюсы:
Минусы: