Я пытаюсь использовать PHP Simple HTML Dom Parser для анализа некоторой информации с некоторых сайтов. Неважно, что и где. Но, похоже, что с ним возникла огромная проблема с памятью. Мне удалось вырезать html-код только на 6 кбайт, но скрипт, который находит некоторые элементы и сохраняет их в базе данных, получает даже 700 МБ оперативной памяти и более 1 ГБ виртуальной памяти! Я где-то читал, что должен использовать -> clear (), чтобы освободить память, но похоже, что это не так.
Я использую str_get_html()
один раз и 5 раз, используя ->find()
присваивая результат переменной.
$main_html = str_get_html($main_site); $x = $main_html->find(...); $y = $main_html->find(...); etc.
Я попытался использовать, например, $y->clear()
после использования $ y, но я получаю ошибку. PHP Fatal error: Call to a member function clear() on a non-object
даже tho $y
существует, и if($y)
истинно. Даже foreach($y) echo $y->plaintext
возвращает plaintext
из $y
.
Из htop:
PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command 8839 username 20 0 1068M 638M 268 R 23.0 8.0 0:08.41 php myscript.php
Что не так?
Простой тест:
echo "(MEM:".memory_get_usage()."->"; $product = $p->find('a',0)->href; echo memory_get_usage()."->"; unset($product); $p->clear(); unset($p); echo memory_get_usage().")";
сecho "(MEM:".memory_get_usage()."->"; $product = $p->find('a',0)->href; echo memory_get_usage()."->"; unset($product); $p->clear(); unset($p); echo memory_get_usage().")";
сecho "(MEM:".memory_get_usage()."->"; $product = $p->find('a',0)->href; echo memory_get_usage()."->"; unset($product); $p->clear(); unset($p); echo memory_get_usage().")";
Результат:
(MEM:11865648->11866192->11865936)
Более читаемая форма:
11865648-> 11866192-> (+544 in total) 11865936 (+288 in total)
Конечно, я не могу использовать $ product-> clear (), так как он говорит, что PHP Fatal error: Call to a member function clear() on a non-object
Кажется, есть некоторые проблемы с памятью при использовании str_html_get
или аналогичной функции, которая создает объект simple_html_dom
несколько раз без очистки и уничтожения предыдущего. Особенно при использовании -> find, который создает массив объектов simple_html_dom_node
. Даже FAQ на сайте авторов говорит, чтобы очистить и уничтожить предыдущий объект simple_html_dom
перед созданием нового, но иногда это невозможно сделать без дополнительного кода и памяти.
Вот почему я создал эту функцию, чтобы удалить все фрагменты PHP Simple HTML Dom Parser из памяти:
function clean_all(&$items,$leave = ''){ foreach($items as $id => $item){ if($leave && ((!is_array($leave) && $id == $leave) || (is_array($leave) && in_array($id,$leave)))) continue; if($id != 'GLOBALS'){ if(is_object($item) && ((get_class($item) == 'simple_html_dom') || (get_class($item) == 'simple_html_dom_node'))){ $items[$id]->clear(); unset($items[$id]); }else if(is_array($item)){ $first = array_shift($item); if(is_object($first) && ((get_class($first) == 'simple_html_dom') || (get_class($first) == 'simple_html_dom_node'))){ unset($items[$id]); } unset($first); } } } }
неfunction clean_all(&$items,$leave = ''){ foreach($items as $id => $item){ if($leave && ((!is_array($leave) && $id == $leave) || (is_array($leave) && in_array($id,$leave)))) continue; if($id != 'GLOBALS'){ if(is_object($item) && ((get_class($item) == 'simple_html_dom') || (get_class($item) == 'simple_html_dom_node'))){ $items[$id]->clear(); unset($items[$id]); }else if(is_array($item)){ $first = array_shift($item); if(is_object($first) && ((get_class($first) == 'simple_html_dom') || (get_class($first) == 'simple_html_dom_node'))){ unset($items[$id]); } unset($first); } } } }
неfunction clean_all(&$items,$leave = ''){ foreach($items as $id => $item){ if($leave && ((!is_array($leave) && $id == $leave) || (is_array($leave) && in_array($id,$leave)))) continue; if($id != 'GLOBALS'){ if(is_object($item) && ((get_class($item) == 'simple_html_dom') || (get_class($item) == 'simple_html_dom_node'))){ $items[$id]->clear(); unset($items[$id]); }else if(is_array($item)){ $first = array_shift($item); if(is_object($first) && ((get_class($first) == 'simple_html_dom') || (get_class($first) == 'simple_html_dom_node'))){ unset($items[$id]); } unset($first); } } } }
сfunction clean_all(&$items,$leave = ''){ foreach($items as $id => $item){ if($leave && ((!is_array($leave) && $id == $leave) || (is_array($leave) && in_array($id,$leave)))) continue; if($id != 'GLOBALS'){ if(is_object($item) && ((get_class($item) == 'simple_html_dom') || (get_class($item) == 'simple_html_dom_node'))){ $items[$id]->clear(); unset($items[$id]); }else if(is_array($item)){ $first = array_shift($item); if(is_object($first) && ((get_class($first) == 'simple_html_dom') || (get_class($first) == 'simple_html_dom_node'))){ unset($items[$id]); } unset($first); } } } }
Применение:
Очистить ВСЕ следы PHP Простой HTML Dom Parser из памяти: clean_all($GLOBALS,'myobj');
Очистите все следы PHP Simple HTML Dom Parser из памяти, кроме $ myobj: clean_all($GLOBALS,'myobj');
Очистите все следы PHP Simple HTML Dom Parser из памяти, за исключением списка объектов ($ myobj1, $ myobj2 …): clean_all($GLOBALS,array('myobj1','myobj2'));
Надеюсь, это тоже поможет другим.
Обычно я использую его, когда я использую str_to_html () два раза:
$site=file_get_contents('http://google.com'); $site_html=str_get_html($site); foreach($site->find('a') as $a){ $site2=file_get_contents($a->href); $site2_html=str_get_html($site2); echo $site2->find('p',0)->plaintext; } clean_all($_GLOBALS);
В этом примере я не могу $site_html->clear()
перед foreach{}
, потому что foreach
затем завершится с ошибкой. И поскольку вызов нескольких str_get_html()
не очищает предыдущие, избыточные зависимости прерываются и очищают его после того, как все утеряны утечки памяти. Вот почему моя функция должна искать определенные переменные для объектов simple_html_dom и очищать их вручную.
В моем случае я форкировал внутри foreach и после нескольких шагов основной скрипт php использовался как 100 МБ памяти. И когда он раздвоился несколько раз, он увеличивался, увеличивался и, наконец, убивал моего сервера до смерти. Ну, почти. Конечно, когда PHP-скрипт заканчивается, он освобождает память. Но при использовании памяти объемом 8 ГБ потребовалось целых возрастов.
Я считаю, вам нужно вызвать clear()
на $main_html
Из документов …
В: Этот сценарий серьезно загрязняет память … После того, как он закончил работу, он не очистит dom-объект должным образом из памяти.
A: Из-за утечки памяти с обратной связью php5 после создания объекта DOM вы должны вызывать $ dom-> clear () для освобождения памяти, если вы вызываете файл_файл__до_ () более одного раза.
Пример:
$html = file_get_html(...); // do something... $html->clear(); unset($html);