以下に触発されて。
パッケージの階層はどこまで深く出来るか
それを調べるために、以下のスクリプトを用意した。
#!/usr/local/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $maxdepth = shift || 1024;
my $ns = 'P';
sub dummy { 1 }
print Dumper \%P::;
for my $i ( 1 .. $maxdepth ) {
no strict 'refs';
local *{ $ns . '::dummy' } = \&dummy;
printf "depth=%d; P::...::dummy=%d\r", $i, &{ $ns . '::dummy' };
$ns .= '::P';
}
print "\n";
print Dumper \%P::;
eval {
no strict 'refs';
warn &{ 'P' . '::' . 'dummy' };
};
warn $@ if $@;
system qw/ps ux -p/, $$;
これを使って調べてみると、答えは「メモリーの持つ限りどこまでも」でOKのようだ。20000ぐらいまでやってみて、使用メモリーが600MBを超えたのでそこで怖じ気づいてそこから先は試していない。
Perlの名前空間(namespace)はどのように実装されているか
ここからが本題。
上のscriptをもう一度よく見てみると、なぜこれほどメモリーを食うのか少し困惑するのではないか。やっている事は名前空間を作って、そこに一時的にサブルーチンを登録しているだけである。それなのに使用メモリーはどんどん増えて行く。なぜだろう。
そこで注目していただきたいのが、Dumperの出力。それだけに注目すると、こうなる。
VAR1 = {};
ループ後
depth=1024; P::...::dummy=1
$VAR1 = {
'P::' => *{'P::P::'},
'dummy' => *P::dummy
};
当初は空っぽだった%P::に何やら入っている。でも%P::ってなんだろ?
これが、Symbol Table Hash, 略して stash だ。一目見ての通り、Stash は名前空間中の変数をキーとする hash になっている。そしてその中のP::というキーに対応する値が、次の名前空間へ参照となっている。別の言い方をすると、$P::P::P::varに一度でもアクセスすると、%P::P::P::というstashだけではなく、%P::P::も%P::も生成されるのだ。
% perl -MData::Dumper -e '$P::P::P::var=1; print Dumper \%P::'
$VAR1 = {
'P::' => *{'P::P::'}
};
そして、ここが重要なのだが、一端生成された stash は、プロセスが死ぬまで解放されない。stash というのは関数定義まで含めたグローバル変数の置き場所なのだからある意味当然ではある。
これもまた、パッケージ変数をも含めたグローバル変数をむやみに使うべきではない理由なのである。
この名前空間と stash に関しては、「ヒョウ本」こと「実用Perlプログラミング」に詳しい。「モダンPerl入門」の方がむしろ「実用」にふさわしい本であるが、原題の"Advanced Perl Programming"のAdvancedなところに関しては今でもこれが書籍としては最もAdvancedな話題を扱っていると思う。
Dan the Perl Monger

このブログにコメントするにはログインが必要です。
さんログアウト
この記事には許可ユーザしかコメントができません。