北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

Test::LeakTrace についてメモ書き

ハマったので未来の自分のためにメモ書きを残しつつ、今年もよろしくお願い致しますm(_ _)m。

Test::LeakTraceの特性

Test::LeakTrace で、以下のテストは通る。

my %x;
no_leaks_ok { $x{x} = undef };

しかし以下のテストは通らない。

my @x;
no_leaks_ok { push @x, undef };

これは、@x にエントリが増えた分がリークとしてカウントされるから。じゃあ前者はなぜ大丈夫なのかというと、no_leaks_ok はブロックを2回実行して2回目でリークをカウントするせい。1回目の実行で%xのバケットが1つ増えるが、2回目以降は再利用するのでリークとしてカウントされない。

あと、次のコードは "not ok 1 - leaks 1 <= 0" と言ってる癖にダンプを表示しない。

my %x;
my $k = 0;
no_leaks_ok {
    $k = ($k + 1) % 2;
    $x{$k} = undef;
};

これはダンプを作る際にさらに改めて2回ブロックを実行する仕組みになっているため。この現象は2回目の呼び出しまではメモリが増加するけど3回目以降は増加しないような場合に起こる。

Test::LeakTrace はこのように複数回ブロックを呼び出してリークを判定・調査する特性があるので、メモリの使い方が安定した状態で呼んだ方が懸命である。

Test::LeakTrace と AnyEvent

AnyEvent のコードはコールバックを中心に書くため、リークしやすい。なので、 Test::LeakTrace でリークしてないことを確かめるのはよいプラクティスだと思う。

しかし AnyEvent は実際の初期化処理を任意のメソッドの使用時にまで遅らせている。そのため、任意のタイミングで初期化処理が走る可能性があり、それが Test::LeakTrace の結果に影響を及ぼすかもしれない。よって、 AnyEvent::detect を先に呼んで初期化を終わらせておいた方が変にハマらずに済む(気がする)。