歴史的にPerlは変数のレキシカルスコープをサポートしており、これによりクロージャ(クロージャ)は外部の環境を保持する関数として使用できます。問題は、クロージャが自分のスコープ外の変数を参照している場合や、ネストされた構造が循環参照を作成する場合に発生し、これがリンクの扱いが不適切なためにメモリリークにつながります。
解決策は、クロージャを使用してファンクションファクトリや関数型スタイルを作成し、その際に外部スコープから変数をクロージャする際のリンクの適切な管理を忘れないことです。
コードの例:
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);
クロージャは常に変数の「コピー」をキャプチャするのですか?それとも同じ変数への参照ですか?
クロージャは常に現在の変数で操作し、そのスコープはクロージャが作成されるときに固定されます。したがって、変数はすべての関数呼び出しで同じです。
クロージャが外部の状態と変更可能な状態で動作し、しかしそれに対して強い参照を持たないようにできますか?
はい、弱い参照(Scalar::Util::weaken)を使用するか、コードの構造を工夫して、参照が必要な場所でのみ保持されるようにします(例えば、クロージャが呼び出されるたびに外部からデータを渡すなど)。
OOオブジェクトから$selfをキャプチャするコールバッククロージャを作成し、callbacksハッシュの中に保持します。オブジェクトが破棄された後、メモリは解放されません。
長所:
短所:
クロージャはScalar::Util::weakenを使用して、$selfに弱い参照を正常に保持します:
use Scalar::Util qw(weaken); my $cb = sub { my $self = shift; weaken($self); ... };
長所:
短所: