以下に触発されて。
パッケージの階層はどこまで深く出来るか
それを調べるために、以下のスクリプトを用意した。
#!/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
このブログにコメントするにはログインが必要です。
さんログアウト
この記事には許可ユーザしかコメントができません。