Perlは自動メモリ管理のために参照カウントアルゴリズムを使用しています:各変数には参照カウントがあります。カウントがゼロになると、メモリは解放されます。ほとんどの場合、これは透過的に機能し、未使用の変数はスコープから外れるとすぐに削除されます。
問題は、循環参照が発生することです(例えば、オブジェクトが自分自身を参照するか、二つの構造が互いに参照し合う場合)。この場合、参照カウントはゼロにならず、メモリは解放されません。
メモリリークを防ぐために、Scalar::Util::weakenモジュールが使用されます — これは、参照カウントを増加させない「弱い」参照を作成できるようにします。
例:
use Scalar::Util qw(weaken); my $a = {}; my $b = { ref => $a }; $a->{ref} = $b; weaken($a->{ref}); # これで循環する強い依存関係がなくなります
Perlは常に未使用のメモリを自動的に解放しますか?複雑な相互参照構造があっても?
回答と例:
いいえ!循環参照がある場合、weakenを使用しない限り、Perlは自動的にメモリを解放できません:
my $a = {}; $a->{self} = $a; # 循環 # $aは自動的には削除されません — 手動での切断または弱い参照が必要です
物語1: 大規模なPerl Webサービスでメモリリークが発生 - ユーザーセッションがお互いをハッシュで参照し合っており、誰も弱い参照を使用していなかった。サービスは一日で全てのリソースを消費し、ハングして再起動を要求しました。
物語2: 自作のORMがUserオブジェクトとGroupオブジェクトの間に循環を作成し、互いに参照し合っていた。スコープを抜けた後もオブジェクトはメモリに残り、サービスは徐々に数十ギガバイトに"膨張"しました!
物語3: クラスメソッドとしての匿名サブルーチン(「クロージャ」)が
$selfを参照することにより、オブジェクトが作成されるたびにメモリリークを引き起こしていました。循環参照を特定し、weakenの必要性を指摘する解析ツールが登場するまでのことでした。