2013-01-24 10 views
7

これは、複雑な方法で大量のデータを処理するPHP 5.3 Cliアプリケーションに関係し、時間がかかります。誰かがガーベジコレクションを無効にすると、それがかなり高速に実行されることを発見しました(たぶん50%程度)。なぜPHPのガーベジコレクタがパフォーマンスを低下させ、メモリなしでメモリを管理するのですか?

このパフォーマンスヒットについては、http://derickrethans.nl/collecting-garbage-performance-considerations.htmlです。私は完全にそれに従っているかどうかはわかりませんが、循環参照が多いコードにのみ適用されることを示唆しています。

誰かがこれでいくつかの光を当てることができますか?

また、gcをオフにしているので、手動でメモリを減らす方法はありますか? unset()を使うことが提案されています。クイックテストでは、オブジェクトのサイズに関係なく、unset()によって80バイト程度が解放されることが示されています。これは、単に私がオンラインで読んだことによって裏づけられた参照を解除することを示唆しています。変数がスコープから外れると、ガベージコレクションがなくても、これらの80バイトが解放されると思うのですか?

答えて

4

循環参照GCを無効にしました。正規のものはまだ動作します。

一般的なGCテストでは、zval(「メモリ」)があるかどうかにかかわらず、どの変数やプロパティからも参照されず、このメモリを解放します。循環参照は、今、両方のオブジェクトが互いを参照するが、それらは両方ともどこから参照されないので、彼らが到達不能であるときに、2つの以上のオブジェクト参照互いに直接、又は間接的

$a = new stdClass; 
$b = new stdClass; 
$a->b = $b; 
$b->a = $a; 
unset($a, $b); 

、です。これは、循環参照GCが検出しようとするものですが、それらを見つけるために、既知のすべてのオブジェクトを反復処理し、「外部から」という参照があるかどうかを調べます。その複雑さは少し複雑ですが、単純化されています;)したがって、多くの参照、特に円形の構造の構造では、それは大きな仕事です。

言及しておくべきこと:unset()では、参照を削除するだけですが、(直接)メモリを解放しないでください。これは後でGCによって行われます(そして良い仕事になります:))

+0

私は、それがケースかもしれないと思ったが、マニュアルは非常に不明瞭です。だから、正規のものは無効にすることは不可能ですか? (興味がありません) – naomi

+0

@naomiはい、無効にすることはできません。あなたはPHPの中からメモリを解放することはできません( 'unset()'はこれをしません)。大きな問題があります:D – KingCrunch

2

unsetを使用してコードから手動でサイクルを削除することができます。 __destruct関数を実装することによって、クラスからのサイクルをクリーンアップします。 unset他のオブジェクトを参照するすべてのプライベート、プロテクト、またはパブリック変数。

既存のプログラムにこれを適用しているのであれば、面倒ですが、実行可能です。


class A { 
    public $ref; 
    public function __destruct() { 
     unset($this->ref); 
     echo "destruct"; 
    } 
} 
$a1 = new A(); 
$a2 = new A(); 
$a1->ref = $a2; 
$a2->ref = $a1; 

これませない作品:

unset($a1, $a2); 
echo "--"; 
// prints --destructdestruct (in 5.3) 

これは動作します:

$a1->__destruct(); 
unset($a1, $a2); 
echo "--"; 
// prints destructdestructdestruct-- (in 5.3) 
+0

あなたは私の ' + 1'を '__destruct()'の2回目の使用に使うと便利です_:D(最初は "リソース、DB接続、ファイルなどを閉じていました。") – KingCrunch

+0

OK、unset()はメモリを解放しませんが、循環参照を削除するので、循環参照コレクタが無効になっているときに(適切な場合)使用することをお勧めします。 – naomi

+0

はい、 'unset'を使ってサイクルを削除することができます。' unset'自体はメモリを解放せず、参照をクリーンアップします。 – Halcyon