HTML::TreeBuilder::XPath + WWW::Mechanize なスクリプトを永続化させようとしてはまった

WWW::Mechanize でコンテンツとってきて TreeBuilder::XPath で解析するようなのを今まで単機能スクリプトなどでは便利に使っていたのだけど、それを永続的なプロセスで使おうとしたらメモリ使いまくってとんでもないことになったという話。

まずどんどんメモリが増えていくのでタイミングよく読んでいたjrockwayの記事などを参考に、

perl -MDevel::Leak::Object=GLOBAL_bless

付きでスクリプトを実行してみる。

少しソースをいじってまずはループを一回で止めるようにしたときの出力

Tracked objects by class:
Config                                   1
DBI                                      1
DBI::var                                 5
DBIx::Class::ResultSource::Table         1
DateTime::Duration                       2
DateTime::Format::Builder::Parser        3
DateTime::Format::Builder::Parser::Regex 10
DateTime::Infinite::Future               1
DateTime::Infinite::Past                 1
DateTime::Locale::en                     1
DateTime::TimeZone::Asia::Tokyo          1
DateTime::TimeZone::Floating             2
Encode::Internal                         1
Encode::utf8                             2
Errno                                    1
FileHandle                               3
HTML::Element                            1799
HTML::Element::_travsignal               5
HTML::TreeBuilder::XPath                 1
XML::XPathEngine                         1
XML::XPathEngine::Expr                   19
XML::XPathEngine::Function               6
XML::XPathEngine::Literal                9
XML::XPathEngine::LocationPath           4
XML::XPathEngine::Root                   1
XML::XPathEngine::Step                   9
utf8                                     2

つぎ、少しループしてから止めたときの出力

Tracked objects by class:
Config                                   1
DBI                                      1
DBI::var                                 5
DBIx::Class::ResultSource::Table         1
DateTime::Duration                       2
DateTime::Format::Builder::Parser        3
DateTime::Format::Builder::Parser::Regex 10
DateTime::Infinite::Future               1
DateTime::Infinite::Past                 1
DateTime::Locale::en                     1
DateTime::TimeZone::Asia::Tokyo          1
DateTime::TimeZone::Floating             2
Encode::Internal                         1
Encode::utf8                             2
Errno                                    1
FileHandle                               3
HTML::Element                            7378
HTML::Element::_travsignal               5
HTML::TreeBuilder::XPath                 4
XML::XPathEngine                         1
XML::XPathEngine::Expr                   19
XML::XPathEngine::Function               6
XML::XPathEngine::Literal                9
XML::XPathEngine::LocationPath           4
XML::XPathEngine::Root                   1
XML::XPathEngine::Step                   9
utf8                                     2

となって、TreeBuilderがなんかやばいことになってるくさい。

で、マニュアル読んでたら $tree->delete やれよ!って書いてあった。

TreeBuilderは明示的にdeleteメソッド呼ばないと綺麗になくならないらしい。たぶん常識なのだが、いままでやってなかったわぁ。。

これやったらずいぶんメモリ増えなくなった、でもまだなんか少しずつ増える。でも、Devel::Leak::Objectの出力は処理数あげてもかわらない。

あとはmechがあやしいなぁとおもって毎回newするようにしたらメモリ増えなくなったのであれれとおもってマニュアル見たら、デフォルトではヒストリを無限に記録していくらしい。

なので

WWW::Mechanize->new( stack_depth => 1 )

とかしたら大丈夫になった。これでとりあえず大丈夫かな。

まぁ結論としては、マニュアル読めということです。あと Devel::Leak::Object は簡単で便利。

by typester / at 2007-09-10T18:51:00 / perl / Comment