CJ7*_*CJ7 4 perl out-of-memory www-mechanize
我在 Perl 中有这个脚本"Out of memory",运行几分钟后出现错误。我看不到任何循环引用,我无法弄清楚为什么会发生这种情况。
use feature 'say';
use WWW::Mechanize;
use HTML::TreeBuilder::XPath;
use utf8;
$url = "some url";
my $mech = new WWW::Mechanize;
$mech->get($url);
my $html = HTML::TreeBuilder::XPath->new_from_content($mech->content);
my $html2;
do {
for $item ($html->findnodes('//li[@class="dataset-item"]'))
{
my $title = $item->findvalue('normalize-space(.//a[2])');
next unless $title =~ /environmental impact statement/i;
my $link = $item->findvalue('.//a[2]/@href');
$mech->get($link);
$html2 = HTML::TreeBuilder::XPath->new_from_content($mech->content);
my @pdflinks = $html2->findvalues('//a[@title="Go to external URL"]/@href');
my $date = $html2->findvalue('//tr[th="Date Created"]/td');
for $pdflink (@pdflinks)
{
next unless $pdflink =~ /\.pdf$/;
$mech->get($pdflink);
$mech->save_content($filename = $mech->response->filename);
say "Title: $title\nDate: $date\nFilename: $filename\n";
}
}
if ($nextpage = $html->findvalue('//ul[@class="pagination"]/li/a[.="»"]/@href'))
{
say "Next Page: $nextpage\n";
$mech->get("some site" . $nextpage);
$html = HTML::TreeBuilder::XPath->new_from_content($mech->content);
}
} while ($nextpage);
say "Completed.";
Run Code Online (Sandbox Code Playgroud)
由于WWW::Mechanize默认情况下具有其用户代理在浏览时保留所有历史记录
- 堆栈深度=>
$value设置跟踪所有下载页面的页面堆栈的深度。默认值实际上是无限的堆栈大小。如果堆栈正在占用您的内存,请将其设置为较小的数字,例如 5 或 10。将其设置为零意味着 Mech 将不保留任何历史记录。
因此,对象不断增长。通过使用Devel::Size qw(total_size)我跟踪的大小,$mech可以看到它在每个 pdf 后增加了数十 kB。剧本显然得到了很多匹配;当它吞噬了 10% 的内存(并且磁盘上有许多超过 Gb 的文件)时,我退出了我的测试。
一种解决方案是为每个 实例化一个新对象$item。这在原则上是浪费的,但实际上它不会增加太多开销,同时会限制最大大小。
或者重置它,或者确实限制它的堆栈深度。由于代码似乎根本不需要回到以前的状态,因此实际上不需要任何堆栈,因此您删除它的解决方案非常好。
注释
准确地说,脚本中没有“泄漏”;它只是需要越来越多的内存
总是有use strict;和use warnings;在脚本的顶部
最好不要使用间接对象语法来实例化对象 ( new Package),而是使用普通的方法调用 ( Package->new),以避免在某些情况下处理歧义。请参阅文档和本页中的解释,以及本帖和本帖中的故障示例。
| 归档时间: |
|
| 查看次数: |
154 次 |
| 最近记录: |