2

PHP Simple HTML Dom Parser を使用して、いくつかのサイトからの情報を解析しようとしています。何をどこにでも構いません。しかし、それには大きなメモリの問題があるようです。HTML コードをわずか 6kB に削減することができましたが、いくつかの要素を見つけてデータベースに保存するスクリプトは、700MB の RAM と 1GB を超える仮想メモリを必要とします! ->clear() を使用してメモリを解放する必要があることをどこかで読みましたが、そうではないようです。

結果を変数に代入して、str_get_html()1回と5回使用します。->find()

$main_html = str_get_html($main_site);
$x = $main_html->find(...);
$y = $main_html->find(...);

etc.

たとえば$y->clear()、 $y を使用した後に使用しようとしましたが、存在しても truePHP Fatal error: Call to a member function clear() on a non-objectであってもエラーが発生します。のリターンもします。$yif($y)foreach($y) echo $y->plaintextplaintext$y

トップから:

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().")";

結果は次のとおりです。

(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

4

2 に答える 2

9

以前のオブジェクトをクリアおよび破棄せずにオブジェクトを数回str_html_get作成する、または同様の関数を使用すると、メモリの問題が発生するようです。simple_html_dom特に、simple_html_dom_nodeオブジェクトの配列を作成する ->find を使用する場合。作成者サイトの 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);
            }
        }
    }
}

使用法:

PHP Simple HTML Dom Parser のすべての痕跡をメモリから消去します。clean_all($GLOBALS);

$myobj を除く、PHP Simple HTML Dom Parser のすべての痕跡をメモリから消去します。clean_all($GLOBALS,'myobj');

オブジェクトのリスト ($myobj1,$myobj2...) を除いて、メモリから PHP Simple HTML Dom Parser のすべてのトレースを消去します。clean_all($GLOBALS,array('myobj1','myobj2'));

それが他の人にも役立つことを願っています。


通常、次のように str_to_html() を 2 回使用するときに使用します。

$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);

この例では、 then は失敗するため、 $site_html->clear()beforeはできません。また、前のものをクリアせずに複数を呼び出すため、冗長な依存関係が壊れており、メモリ リークが発生した後にそれをクリアします。そのため、私の関数は定義済みの変数で simple_html_dom オブジェクトを検索し、それらを手動でクリアする必要があります。foreach{}foreachstr_get_html()

私の場合、foreach 内でフォークし、いくつかの手順を実行した後、メインの php スクリプトが 100MB のメモリを使用しました。そして、数回分岐すると、それはますます増加し、最終的にサーバーを殺してしまいました。よくほとんど。もちろん、PHP スクリプトが終了すると、メモリが解放されます。しかし、8GBのメモリを使用すると、終了するのに何年もかかりました.

于 2013-08-07T05:29:38.857 に答える
2

電話する必要があると思いclear()ます$main_html

ドキュメントから...

Q: このスクリプトは深刻なメモリ リークを起こしています...実行が終了した後、メモリから dom オブジェクトを適切にクリーンアップしていません..

A: PHP5 の循環参照のメモリ リークにより、DOM オブジェクトを作成した後、複数回$dom->clear()呼び出す場合は、呼び出してメモリを解放する必要があります。file_get_dom()

例:

$html = file_get_html(...); 
// do something... 
$html->clear(); 
unset($html);
于 2013-08-06T20:52:39.983 に答える