簡體   English   中英

Memory 使用 WWW::Mechanize 泄漏

[英]Memory leak using 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.";

由於WWW::Mechanize默認情況下其用戶代理在瀏覽時保留所有歷史記錄

  • stack_depth => $value

設置跟蹤所有下載頁面的頁面堆棧的深度。 默認值實際上是無限堆棧大小。 如果堆棧耗盡了您的 memory,則將其設置為較小的數字,例如 5 或 10。將其設置為零意味着 Mech 將不保留任何歷史記錄。

因此 object 不斷增長。 通過使用Devel::Size qw(total_size)我跟蹤$mech的大小,以查看它在每個 pdf 之后增加了數十 kB。 而且腳本顯然有很多匹配項; 當它吞噬了 memory 的 10%(並且磁盤上有許多超過 Gb 的文件)時,我退出了我的測試。

然后一種解決方案是為每個$item實例化一個新的 object 。 這在原則上是浪費的,但實際上並不會增加太多開銷,同時會限制最大大小。

或者重置它,或者確實限制它的堆棧深度。 由於代碼似乎不需要 go 回到以前的狀態,因此根本不需要任何堆棧,因此您刪除它的解決方案非常好。

注釋

  • 准確地說,腳本中沒有“泄漏”; 只是需要越來越多的 memory

  • 始終use strict; use warnings; 在腳本的頂部

  • 最好不要使用間接 object 語法來實例化 object ( new Package ),而是使用普通方法調用(在某些情況下是Package->new ),以避免處理歧義。 請參閱文檔此頁面中的說明,以及此帖子此帖子中的問題示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM