ホームページ >バックエンド開発 >PHPチュートリアル >PHP のメモリ リーク問題とガベージ コレクション_PHP チュートリアル
PHP スクリプトを作成する場合、通常、スクリプトはすぐに実行を完了して終了するため、メモリ リークやガベージ コレクションについて心配する必要はありません。
しかし、実行時間が長く、データ量が多い場合、プログラムが一定時間実行されると、PHP スクリプトはメモリを大量に消費し、エラーで終了します (PHP 致命的エラー: 許容メモリ サイズ134217728 バイトを使い果たしました)。一般に、各ページの処理が完了した後、新しく作成された simple_html_dom オブジェクトは破棄されるはずですが、実際にはメモリ リークが発生していないことは明らかです。
PHP 5.3 より前に使用されていたガベージ コレクション メカニズムは、単純な「参照カウント」です。つまり、メモリ オブジェクトが変数によって参照される場合、変数の参照が削除されると、カウンター + 1 が割り当てられます。カウンタ - 1 ; カウンタ = 0 の場合、メモリ オブジェクトが使用されていないことを示し、メモリ オブジェクトは破棄され、ガベージ コレクションが完了します。
「参照カウント」には問題があります。つまり、2 つ以上のオブジェクトが相互に参照してリングを形成する場合、この時点でメモリ オブジェクトのカウンタは 0 に減りません。は役に立たなくなりましたが、リサイクルできないため、メモリ リークが発生します。
PHP 5.3 以降、参照カウントに基づいた新しいガベージ コレクション メカニズムが使用され、メモリ リークを回避するためにメモリ オブジェクト内の参照リングの存在を検出するための複雑なアルゴリズムが実装されました。
解放されるべきであるが解放されていないメモリがあるかどうかを確認するには、memory_get_usage 関数を呼び出してメモリ使用量を確認します。memory_get_usage 関数によって返されるメモリ使用量データはあまり正確ではありません。 php の xdebug 拡張機能を使用すると、より正確で有益なメモリ使用量の情報を取得できます。
リーリー上記は、循環参照を生成する例を構築します。 A オブジェクトのインスタンス a が作成されるたびに、a は B オブジェクトのインスタンス b を作成し、b に a を参照させます。このようにして、各 A オブジェクトは常に B によって参照され、各 B オブジェクトは同時にオブジェクト A によって参照されます。これが参照ループの作成方法です。
このコードを php5.2 環境で実行すると、メモリ使用量が単調に増加しており、A と B のデストラクタが実行された後、メモリが空になるまで「A/B desctruct」情報が出力されないことがわかります。使い果たされました。「PHP 致命的エラー: 許容メモリ サイズ 134217728 バイトが使い果たされました (40 バイトを割り当てようとしました)」。
このコードをphp5.3環境で実行すると、メモリ使用量が上下に跳ね上がりますが、制限を超えることはありません。また、プログラムは、デストラクターが呼び出されたことを示す「A/B desctruct」を大量に出力します。
私の同僚のプログラムにはこの種の参照ループがあり、彼のスクリプトは実際にはphp5.2.3で実行されます。 simple_html_dom ツールには、simple_html_dom と simple_html_dom_node という 2 つのクラスがあり、前者には配列メンバー変数ノードがあり、配列内の各要素は simple_html_dom_node オブジェクトであり、各 simple_html_dom_node オブジェクトにはメンバー変数 dom があり、その値は次のとおりです。以前の simple_html_dom オブジェクト - したがって、美しい参照ループが形成され、メモリ リークが発生します。解決策も非常に簡単です。つまり、simple_html_dom オブジェクトの使用が終了し、そのクリア関数を積極的に呼び出してそのメンバー変数ノードをクリアすると、ループが中断され、メモリ リークは発生しません。
1.ガベージコレクションのタイミング
PHPでは参照カウントが0になるとすぐにメモリが解放されます。つまり、変数への循環参照がない場合、メモリは変数のスコープから出た直後に解放されます。循環リファレンス検出は特定の条件が満たされたときにトリガーされるため、上記の例では、使用されるメモリに大きな変動が見られます。 gc_collect_cycles 関数を使用して、循環参照を積極的に検出することもできます。
2. アンパサンドの影響
変数を明示的に参照すると、そのメモリの参照カウントが増加します:
リーリーこの時点ではunset($a)していますが、メモリ領域を指す$bへの参照が残っており、メモリは解放されません。
3. 未設定機能の影響
unset は変数をメモリ領域から切断し、メモリ領域の参照カウントを -1 減らすだけです。上記の例では、ループ本体内では $a=new A(); は行われません。 $a の参照カウントをゼロに減らします
;4. null 操作の影響
$a = null は、$a が指すデータ構造を直接 null にし、その参照カウントを 0 に返します。
5. スクリプト実行終了の影響
スクリプトの実行が終了すると、参照サイクルの有無に関係なく、スクリプトで使用されていたすべてのメモリが解放されます。