先日、作成中のCatalystアプリにおいてメモリリークが観測されました。
原因は、

use Template::Plugin;
use base qw(Template::Plugin);

sub new {
    my ($class, $context, $args) = @_;

    my $self = {
      _CONTEXT => $context,
      _STASH => $context->stash,
    };

    bless $self , $class;
}

としているところの、

    _STASH => $context->stash

の部分で循環参照となってしまい、リークを起してしまったようです。

この問題によって、Catalyst::View::TTの、sub renderでの $tt->process()
で作成された$output(=画面に出力すべきHTML)が、
リクエスト終了後も開放されず、蓄積されていってしまったのでした。

循環参照の詳しい状況は再度追って報告します。

GTop

今回はGTopモジュールでメモリの推移を把握し、
ボトルネックを突き止めるアプローチを行ないました。

MyApp.pmに以下を追加します。

use GTop;
sub prepare {
    my ( $class, $args) = @_;

    my $gtop = GTop->new;
    my $memory_in_start = $gtop->mem($$)->size;
    my $c = $class->Super::prepare( $args );

    $c->stash->{gtop} = $gtop;
    $c->stash->{memory_in_start} = $memory_in_start;

    return $c;
}

sub finalize_body {
    my ( $class, $c ) = @_;

    $class->Super::finalize_body( $c );
    $c->stash->{memory_in_end} = $c->stash->{gtop}->mem($$)->size;
    $c->log->debug( "Diff:" . 
         GTop::size( $c->stash->{memory_in_end} - $c->stash->{memory_in_start}) );   
}

これで、リクエストに対する処理が終了するまでのメモリの推移が、ログに出力されます。

Catalyst,FCGIのメモリ推移

GTopモジュールで分かったことは、

  1. myapp_fcgi.pl起動後の1リクエスト目で、かなりのメモリ量を使用するということ。
  2. そして、次のリクエストからはほとんどメモリを消費しないということ。

この現象を理解したい。(誰か教えてw