ホームページ  >  記事  >  バックエンド開発  >  PHP オブジェクトが相互参照する場合のメモリ オーバーフロー_PHP チュートリアル

PHP オブジェクトが相互参照する場合のメモリ オーバーフロー_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-13 17:36:44778ブラウズ

スクリプト言語を使用する最大の利点の 1 つは、その自動ガベージ コレクション メカニズム (メモリの解放) を利用できることです。変数を使用した後にメモリを解放するための処理を行う必要はありません。PHP が自動的に実行します。もちろん、必要に応じて unset() 関数を呼び出してメモリを解放することもできますが、通常はその必要はありません。
ただし、PHP では、unset() を手動で呼び出した場合でも、メモリが自動的に解放されない状況が少なくとも 1 つあります。詳細については、http://bugs.php.net/bug.php?id=33595 を参照してください。

問題の症状

「親オブジェクトと子オブジェクト」など、2 つのオブジェクト間に相互参照関係がある場合、親オブジェクトで unset() を呼び出しても、子オブジェクトで親オブジェクトを参照しているメモリは解放されません (たとえ親オブジェクトはガベージ コレクションも行いません)。
少し混乱していますか?次のコードを見てみましょう:

bar = new Bar($this);}}class Bar {function __construct($foo = null){$this->foo = $foo; }}while (true) {$foo = new Foo();unset($foo);echonumber_format(memory_get_usage()) 。 ";}?>このコードを実行すると、メモリ使用量が使い果たされるまでどんどん増えていくことがわかります。

...33,551,61633,551,97633,552,33633,552,696PHP 致命的なエラー: memleak.php の 17 行目で、33554432 バイトの許容メモリ サイズが使い果たされました (16 バイトを割り当てようとしました) ほとんどの PHP プログラマーにとって、この状況はそうではありません。問題。

ただし、実行時間の長いコードで相互参照するオブジェクトを多数使用する場合、特にオブジェクトが比較的大きい場合は、メモリがすぐに消費されます。

ユーザーランド ソリューション

少し面倒で洗練されていませんが、前述の bugs.php.net リンクにソリューションが提供されています。
このソリューションでは、目的を達成するためにオブジェクトを解放する前にデストラクター メソッドを使用します。 Destructor メソッドはすべての内部親オブジェクト参照をクリアできます。これは、そうでなければオーバーフローするメモリのこの部分を解放できることを意味します。
「修正された」コードは次のとおりです:

bar = new Bar($this);}function __destruct(){unset($this->bar);}}class Bar {function __construct( $foo = null){$this->foo = $foo;}}while (true) {$foo = new Foo();$foo->__destruct();unset($foo);echonumber_format(memory_get_usage ())」 ";}?>新しい Foo::__destruct() メソッドと、オブジェクトを解放する前の $foo->__destruct() の呼び出しに注意してください。これで、このコードはメモリ使用量の増加の問題を解決します。このようにして、コードはうまくいきます

PHP カーネル ソリューション?

なぜメモリオーバーフローが発生するのですか?私は PHP カーネルの研究には詳しくありませんが、この問題は参照カウントに関連していると確信しています。
親オブジェクト $foo が解放されるため、$bar で参照される $foo の参照カウントはデクリメントされません。この時点で、PHP は $foo オブジェクトがまだ必要であると判断するため、メモリのこの部分は解放されません。 ..おそらく。
ここでは私の無知が露呈していますが、一般的な考え方は、参照カウントはデクリメントされないため、一部のメモリは解放されないということです。
前述の bugs.php.net リンクで、ガベージ コレクション プロセスを変更するとパフォーマンスが大幅に犠牲になることがわかりましたが、参照カウントについてはあまり詳しくないので、これが真実だと思いました。
ガベージ コレクション プロセスを変更する代わりに、unset() を使用して内部オブジェクトを解放してみてはいかがでしょうか? (または、オブジェクトを解放するときに __destruct() を呼び出しますか?)
おそらく、PHP カーネル開発者は、このガベージ コレクション処理メカニズムをここまたは他の場所で変更できるでしょう。
更新: Martin Fjordvald がコメントで、David Wang がガベージ コレクション用に作成したパッチについて言及しました (実際には、「一枚の布全体」のように見えますが、非常に巨大です。詳細については、このメールの最後にある CVS エクスポート情報を参照してください)。これは実際に存在し (電子メール)、PHP カーネル開発メンバーの注目を集めています。問題は、このパッチを PHP5.3 に入れるべきかどうかですが、あまりサポートされていません。良い妥協策は、unset() 関数のオブジェクトで __destruct() メソッドを呼び出すことだと思います。

http://www.bkjia.com/PHPjc/508217.html

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/508217.html技術記事スクリプト言語を使用する最大の利点の 1 つは、その自動ガベージ コレクション メカニズム (メモリの解放) を利用できることです。変数を使用した後にメモリを解放するために何もする必要はありません。PHP は...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。