Утечка памяти с использованием WWW :: Mechanize - PullRequest
4 голосов
/ 07 мая 2020

У меня есть этот сценарий в 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.";

1 Ответ

8 голосов
/ 07 мая 2020

Так как WWW :: Mechanize по умолчанию имеет свой пользовательский агент, сохраняющий всю историю при просмотре

  • stack_depth => $value

Устанавливает глубину стека страниц, которая отслеживает все загруженные страницы. По умолчанию размер стека фактически бесконечен. Если стек поглощает вашу память, то установите меньшее число, скажем 5 или 10. Установка этого значения на ноль означает, что мех не будет хранить историю.

Таким образом, объект продолжает расти. Используя Devel::Size qw(total_size), я отслеживаю размер $mech, чтобы увидеть, что он добавляет десятки килобайт после каждого PDF-файла. И сценарий явно находит много совпадений; Я завершил свой тест, когда он сожрал 10% памяти (и на диске было много десятков файлов размером более Гб). . В принципе, это расточительно, но на самом деле это не увеличивает накладных расходов, хотя и ограничивает максимальный размер.

Или сбросить его, или действительно ограничить глубину его стека. Поскольку код, похоже, не нуждается в go возвращении к предыдущим состояниям, на самом деле нет необходимости в каком-либо стеке, поэтому ваше решение сбросить его вполне подойдет.

Комментарии

  • Точнее "утечки" в скрипте нет; просто требуется все больше и больше памяти

  • Всегда иметь use strict; и use warnings; в верхней части скрипта

  • Лучше не использовать синтаксис косвенного объекта для создания экземпляра объекта (new Package), а использовать обычный вызов метода (Package->new), чтобы в некоторых случаях избежать неоднозначности. См. Объяснение в документах и этой странице , а также примеры проблем в этом сообщении и этом сообщении .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...