PHP Простой HTML-файл Parser Memory Leak / Usage

Я пытаюсь использовать 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);