スクリプト言語を使用する最大の利点の 1 つは、その自動ガベージ コレクション メカニズム (メモリの解放) を利用できることです。変数を使用した後にメモリを解放するための処理を行う必要はありません。PHP が自動的に実行します。もちろん、必要に応じて unset() 関数を呼び出してメモリを解放することもできますが、通常はその必要はありません。 「親オブジェクトと子オブジェクト」など、2 つのオブジェクト間に相互参照関係がある場合、親オブジェクトで unset() を呼び出しても、子オブジェクトで親オブジェクトを参照しているメモリは解放されません (たとえ親オブジェクトはガベージ コレクションも行いません)。
ただし、実行時間の長いコードで相互参照するオブジェクトを多数使用する場合、特にオブジェクトが比較的大きい場合は、メモリがすぐに消費されます。 少し面倒で洗練されていませんが、前述の bugs.php.net リンクにソリューションが提供されています。 。
なぜメモリオーバーフローが発生するのですか?私は PHP カーネルの研究には詳しくありませんが、この問題は参照カウントに関連していると確信しています。
ただし、PHP では、unset() を手動で呼び出した場合でも、メモリが自動的に解放されない状況が少なくとも 1 つあります。詳細については、http://bugs.php.net/bug.php?id=33595 を参照してください。
少し混乱していますか?次のコードを見てみましょう:
このソリューションでは、目的を達成するためにオブジェクトを解放する前にデストラクター メソッドを使用します。 Destructor メソッドはすべての内部親オブジェクト参照をクリアできます。これは、そうでなければオーバーフローするメモリのこの部分を解放できることを意味します。
「修正された」コードは次のとおりです:
親オブジェクト $foo が解放されるため、$bar で参照される $foo の参照カウントはデクリメントされません。この時点で、PHP は $foo オブジェクトがまだ必要であると判断するため、メモリのこの部分は解放されません。 ..おそらく。
ここでは私の無知が露呈していますが、一般的な考え方は、参照カウントはデクリメントされないため、一部のメモリは解放されないということです。
前述の bugs.php.net リンクで、ガベージ コレクション プロセスを変更するとパフォーマンスが大幅に犠牲になることがわかりましたが、参照カウントについてはあまり詳しくないので、これが真実だと思いました。
ガベージ コレクション プロセスを変更する代わりに、unset() を使用して内部オブジェクトを解放してみてはいかがでしょうか? (または、オブジェクトを解放するときに __destruct() を呼び出しますか?)
おそらく、PHP カーネル開発者は、このガベージ コレクション処理メカニズムをここまたは他の場所で変更できるでしょう。
更新: Martin Fjordvald がコメントで、David Wang がガベージ コレクション用に作成したパッチについて言及しました (実際には、「一枚の布全体」のように見えますが、非常に巨大です。詳細については、このメールの最後にある CVS エクスポート情報を参照してください)。これは実際に存在し (電子メール)、PHP カーネル開発メンバーの注目を集めています。問題は、このパッチを PHP5.3 に入れるべきかどうかですが、あまりサポートされていません。良い妥協策は、unset() 関数のオブジェクトで __destruct() メソッドを呼び出すことだと思います。