Утечка памяти phpQuery. Как исправить?

108
13 января 2021, 23:10

Есть функция, которая, используя библиотеку phpQuery, парсит данные со страницы на сайте. Данные на странице обновляются регулярно, поэтому функция вызывается в цикле приблизительно каждые 5-10 секунд (в зависимости от скорости получения страницы). После продолжительной работы скрипта, получаю ошибку

PHP Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 1073741824 bytes) in C:\OSPanel\domains\home-page-parcer.ru\phpQuery.php on line 3494

В php.ini memory_limit = 1536M. Скрипт работает на локальном сервере (OpenServer).

Провел небольшие исследования расставив в различных частях скрипта memory_get_usage. Потребляемая память увеличивается непосредственно после создания объекта phpQuery или после одного из циклов foreach (1-го либо 2-го сверху) , при этом память не уменьшается после вызова phpQuery::unloadDocuments(). Также, память накапливается не после каждого создания объекта phpQuery, а как-то периодически (один раз в несколько итераций, закономерность увеличения не удалось установить). К примеру: было 2097152 после стало 4194304, спустя несколько итераций значение не изменялось, но после снова увеличилось и стало 6291456.

Собственно сама функция. Не могу понять в чем проблема и почему phpQuery::unloadDocuments(); не работает

function parcer($url){
    $ids=[];
    $indexIds=0;
    $content = get_content($url);
    $doc = phpQuery::newDocument($content);
    foreach ($doc->find('[id^=name_]:input') as $opt) { // получаем товары которые успели преобразоваться в input
            $opt=pq($opt);
            $numTov = preg_replace('~[^0-9]*~','',$opt->attr('id')); // получаем с ID номер товара
            $ids[$indexIds][] = $numTov;
            $ids[$indexIds][] = $opt->attr('value'); // получаем значение input
            $ids[$indexIds][] = $opt->nextAll('input:first-of-type')->prev('a')->text(); //ищем последнюю ссылку каталога
            $ids[$indexIds][] = $opt->nextAll('nobr')->children('[id^=manf]')->text(); //ищем поставщика
            $indexIds++;
    }
    foreach ($doc->find('td>[id^=name_]:not(:input)') as $opt) { // получаем товары в span, которые без родителя
            $opt=pq($opt);
            $numTov = preg_replace('~[^0-9]*~','',$opt->attr('id'));
            $ids[$indexIds][] = $numTov;
            $ids[$indexIds][]= $opt->text();
            $ids[$indexIds][] = $opt->nextAll('[id^=cats_]:last')->text();
            $ids[$indexIds][] = $opt->nextAll('nobr')->children('[id^=manf]')->text();
            $indexIds++;
    }
    foreach ($doc->find('div>[id^=name_]') as $opt) { // получаем товары в span, которые с родителем
            $opt=pq($opt);
            $numTov = preg_replace('~[^0-9]*~','',$opt->attr('id'));
            $ids[$indexIds][] = $numTov;
            $ids[$indexIds][]= $opt->text();
            $ids[$indexIds][] = $opt->parent()->nextAll('[id^=cats_]:last')->text();
            $ids[$indexIds][] = $opt->parent()->nextAll('nobr')->children('[id^=manf]')->text();
            $indexIds++;
    }
    phpQuery::unloadDocuments(); //очистка документа
    gc_collect_cycles(); // принудительный вызов встроенного сборщика мусора PHP
    return $ids;
    }
Answer 1

Да уж... Получу я от "маститых" разрабов минуса, но тем не менее:

  1. Присвойте $doc->find("") переменной, а потом уже с ней работайте.
  2. В конце каждого цикла используйте unset($opt).
  3. Попробуйте "вырезать" весь ненужный мусор со страницы, облегчив итоговый документ.
READ ALSO
Не отправляется форма HTML+PHP

Не отправляется форма HTML+PHP

Никак не могу разобраться в проблеме отправки формы: нажимаю Save и не отправляется

89
PHP выделение блоков из текста по ключу

PHP выделение блоков из текста по ключу

Доброе время суток! Требуется помощь, есть данные которые приходят из формы, пример данных:

79