Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: phpQuery. Проблема с памятью
Форумы портала PHP.SU » PHP » Программирование на PHP » phpQuery. Проблема с памятью

Страниц (1): [1]
 

1. mikka - 26 Мая, 2019 - 14:35:06 - перейти к сообщению
Добрый день!

Есть функция, которая, используя библиотеку phpQuery, парсит данные со страницы на сайте. Данные на странице обновляются регулярно, поэтому функция вызывается в цикле приблизительно каждые 5-10 секунд (в зависимости от скорости получения страницы). После продолжительной работы скрипта (приблизительно 8-10 часов, при этом ~3-5 часов из этого времени ноутбук я не трогал), получаю ошибку (забыл ее скопировать с логов), что не хватает памяти для работы phpQuery. В php.ini memory_limit = 1536M. Скрипт работает на локальном сервере (OpenServer). В диспетчере задач объем памяти потребляемый Apache HTTP Server постоянно колеблется, к примеру: несколько минут назад (после небольшого простоя бездействия ноутбука было 170Мб), сейчас (спустя минут 10) - 60 Мб. Собственно сама функция. Не могу понять в чем проблема и почему phpQuery::unloadDocuments(); как-то избирательно очищает документы
PHP:
скопировать код в буфер обмена
  1. function parcer($url){
  2. $ids=[];
  3. $indexIds=0;
  4. $content = get_content($url);
  5.  
  6. $doc = phpQuery::newDocument($content);
  7.  
  8. foreach ($doc->find('[id^=name_]:input') as $opt) { // получаем товары которые успели преобразоваться в input
  9.         $opt=pq($opt);
  10.         $numTov = preg_replace('~[^0-9]*~','',$opt->attr('id')); // получаем с ID номер товара
  11.         $ids[$indexIds][] = $numTov;
  12.         $ids[$indexIds][] = $opt->attr('value'); // получаем значение input
  13.         $ids[$indexIds][] = $opt->nextAll('input:first-of-type')->prev('a')->text(); //ищем последнюю ссылку каталога
  14.         $ids[$indexIds][] = $opt->nextAll('nobr')->children('[id^=manf]')->text(); //ищем поставщика
  15.         $indexIds++;
  16. }
  17.  
  18. foreach ($doc->find('td>[id^=name_]:not(:input)') as $opt) { // получаем товары в span, которые без родителя
  19.         $opt=pq($opt);
  20.         $numTov = preg_replace('~[^0-9]*~','',$opt->attr('id'));
  21.         $ids[$indexIds][] = $numTov;
  22.         $ids[$indexIds][]= $opt->text();
  23.         $ids[$indexIds][] = $opt->nextAll('[id^=cats_]:last')->text();
  24.         $ids[$indexIds][] = $opt->nextAll('nobr')->children('[id^=manf]')->text();
  25.         $indexIds++;
  26. }
  27.  
  28. foreach ($doc->find('div>[id^=name_]') as $opt) { // получаем товары в span, которые с родителем
  29.         $opt=pq($opt);
  30.         $numTov = preg_replace('~[^0-9]*~','',$opt->attr('id'));
  31.         $ids[$indexIds][] = $numTov;
  32.         $ids[$indexIds][]= $opt->text();
  33.         $ids[$indexIds][] = $opt->parent()->nextAll('[id^=cats_]:last')->text();
  34.         $ids[$indexIds][] = $opt->parent()->nextAll('nobr')->children('[id^=manf]')->text();
  35.         $indexIds++;
  36. }
  37.  
  38. phpQuery::unloadDocuments(); //очистка документа
  39. gc_collect_cycles(); // принудительный вызов встроенного сборщика мусора PHP
  40. return $ids;
  41. }
2. LIME - 27 Мая, 2019 - 17:56:34 - перейти к сообщению
а возможно и где-то еще течет вне это ф-ции
выводи в консоль отладочную инфу
https://www.php.net/manual/ru/fu...ry-get-usage.php
в начале ф-ции, вне ф-ции, перед и после unloadDocuments итд
может надебажишь что
(Добавление)
я бы конечно вовнутрь полез и посмотрел что он там кэширует и как
в newDocument и unloadDocuments если выяснишь что именно он течет
3. mikka - 27 Мая, 2019 - 19:46:33 - перейти к сообщению
LIME пишет:
а возможно и где-то еще течет вне это ф-ции
выводи в консоль отладочную инфу
https://www.php.net/manual/ru/fu...ry-get-usage.php
в начале ф-ции, вне ф-ции, перед и после unloadDocuments итд
может надебажишь что
(Добавление)
я бы конечно вовнутрь полез и посмотрел что он там кэширует и как
в newDocument и unloadDocuments если выяснишь что именно он течет


В том что дело phpQuery используется только в этой функции и больше нигде.
Вот снова получил эту ошибку

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

Спасибо за совет с памятью. Буду пытаться отладить.
4. LIME - 27 Мая, 2019 - 20:34:07 - перейти к сообщению
В какой момент закончилась память само по себе еще ничего не значит
Если используется фреймворк запусти в прод режиме
Они много всего пишут в профилировщик
Только выводит память чтоб не ждать до утра))
(Добавление)
Если все-таки случится затык
Запускай внутри цикла дочерний процесс передавая урл как параметр
Заодно распарраллелишь))
5. mikka - 28 Мая, 2019 - 11:56:24 - перейти к сообщению
Провел небольшие исследования расставив в различных частях скрипта memory_get_usage.
Потребляемая память увеличивается непосредственно после создания объекта phpQuery из переменной $content , при этом память не уменьшается после вызова phpQuery::unloadDocuments(). Также, память накапливается не после каждого создания объекта phpQuery, а как-то периодически (один раз в несколько итераций, закономерность увеличения не удалось установить). К примеру: было 2097152 после стало 4194304, спустя несколько итераций значение не изменялось, но после снова увеличилось и стало 6291456.
Также хотелось бы добавить, что в некоторых случаях, память увеличивается не после создания объекта phpQuery, а после одного из циклов foreach (1-го либо 2-го сверху)

 

Powered by ExBB FM 1.0 RC1