Perlは参照カウントを通じて自動メモリ管理を行います。ネストされた構造(例えばハッシュ内の配列)を構築すると、任意のコンテナの各要素は特定のオブジェクトへの参照数を増減させます。参照数がゼロになると、メモリは自動的に解放されます。
特に注意が必要なのは循環参照で、Perlはこれを自動的に解放することができません。これはネストされた構造での典型的な罠です。PerlはScalar::Utilモジュールを通じて弱い参照をサポートしており、これにより循環を断ち切ることが可能です:弱い参照は参照カウントを増やしません。
my %hash_of_arrays; $hash_of_arrays{"nums"} = [1,2,3]; $hash_of_arrays{"words"} = ["apple", "banana"];
my $a = {}; my $b = { next => $a }; $a->{next} = $b; # ここで循環が発生 dump($a); # Data::Dumperを使用して構造を表示
メモリリークを避けるために、弱い参照を使用します:
use Scalar::Util qw(weaken); $a->{next} = $b; weaken($a->{next}); # これで $a->{next} は弱い参照になります
Perlで循環的に関連付けられた配列とハッシュ間の外部変数を削除した場合、メモリに何が起こりますか?
正しい答え: どのオブジェクトの参照カウントもゼロにはならず、それぞれがお互いに参照し合っているため、メモリは解放されず、メモリリークが発生します! 循環を手動で断ち切る必要があります(例えば、弱い参照を使って)。
my $arr = []; my $h = { arr => $arr }; push @$arr, $h; # これで $arr と $h は循環を形成します。 undef $arr; undef $h; の後、メモリは解放されません。
物語
物語
物語
CGIアプリケーション内でキャッシングを実装する際、複雑な相互関係を持つ構造(配列とハッシュ)を使用することに決めました。古い値を適切にゼロにしなかったため、配列の一部の要素が構造全体のハッシュを参照し続け、HTTPリクエスト間でメモリが解放されず、Apacheプロセスのメモリが増加しました。