ホームページ  >  記事  >  バックエンド開発  >  PHPのガベージコレクションの仕組みを詳しく解説_PHPチュートリアル

PHPのガベージコレクションの仕組みを詳しく解説_PHPチュートリアル

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

PHP は自動的にメモリを管理し、不要になったオブジェクトを消去できます。 PHP は、単純なガベージ コレクション メカニズムである参照カウントを使用します。各オブジェクトには参照カウンタが含まれており、オブジェクトに接続されている参照ごとにカウンタが 1 ずつ増加します。参照がリビング スペースを離れるか、NULL に設定されると、カウンターは 1 ずつ減らされます。オブジェクトの参照カウンタがゼロになると、PHP はそのオブジェクトを使用する必要がなくなったことを認識し、PHP 5.3 より前に使用されていたガベージ コレクション メカニズムは単純な「参照カウント」でした。各メモリ オブジェクトにはカウンタが割り当てられます。メモリ オブジェクトが変数によって参照されている場合、カウンタは +1 になり、カウンタ = 0 の場合、カウンタは -1 になります。使用されず、メモリ オブジェクトは破棄されます。

「参照カウント」には問題があります。つまり、2 つ以上のオブジェクトが相互に参照してリングを形成する場合、この時点でメモリ オブジェクトのカウンタは 0 に減りません。役に立たなくなりましたが、リサイクルできないため、メモリ リークが発生します;

PHP 5.3 以降、参照カウントに基づいた新しいガベージ コレクション メカニズムが使用され、メモリ リークを回避するためにメモリ オブジェクト内の参照リングの存在を検出するための複雑なアルゴリズムが実装されました。

php 変数は、「zval」という変数コンテナーに存在します。「zval」変数コンテナーには、変数の型と値が含まれており、また、変数が参照であるかどうかを示す 2 バイトの追加情報も含まれています。 "refcount" "この zval 変数コンテナーを指す変数の数。

xdebug がインストールされている場合は、xdebug_debug_zval() を使用して「zval」情報を表示できます。以下の通り:

$str = "www.bKjia.c0m";
xdebug_debug_zval('str');

結果:

文字列:

(refcount=1, is_ref=0),

文字列「phpddt.com」(長さ=10)

「refcount」が 0 になるときに変数コンテナが破棄される場合のみ。変数を unset() すると、目的の「zval」の refcount が 1 減ります。数日前に発生した参照の設定解除について話しましょう 質問:

コードは次のとおりですコードをコピー
$a = "ああ";
$b = & $a;
unset($a);
//echo $b; //aaa はここでも出力されます。xdebug_debug_zval で出力すると、理由がわかります
xdebug_debug_zval("b");

結果:

b:

(refcount=1, is_ref=0),文字列 'aaa' (長さ=3)

参照カウンタの問題についての説明を続けますが、配列とオブジェクト型では状況が異なります。

コードは次のとおりですコードをコピー

$arr = array( 'a' => 'aaa', 'b' => "bbb" );
xdebug_debug_zval( 'arr' );
$arr['aaa'] = $arr['a'];
xdebug_debug_zval( 'arr' );
?>

結果:

編曲:

(refcount=1, is_ref=0),

配列

'a' => (refcount=1, is_ref=0),string 'aaa' (length=3)

'b' => (refcount=1, is_ref=0),string 'bbb' (length=3)

編曲:

(refcount=1, is_ref=0),

配列

'a' => (refcount=2, is_ref=0),string 'aaa' (length=3)

'b' => (refcount=1, is_ref=0),string 'bbb' (length=3)

'aaa' => (refcount=2, is_ref=0),文字列 'aaa' (length=3)


元の配列要素と新しく追加された配列要素が、「refcount」2 の同じ zval 変数コンテナに関連付けられていることがわかります。ここでは、他の人にインスピレーションを与えようとしているだけです。

上記では、単に unset、null、mysql_close、__destruct、xdebug_debug_zval を使用してから読み続けました


メモリリークがないか確認してください

解放されるべきであるが解放されていないメモリがあるかどうかを確認するには、memory_get_usage 関数を呼び出してメモリ使用量を確認します。memory_get_usage 関数によって返されるメモリ使用量データはあまり正確ではありません。より正確で有益なメモリ使用量データを取得するには、PHP の xdebug 拡張機能を使用します。

コードは次のとおりです コードをコピー

クラスA{
プライベート $b;
関数 __construct(){
$this->b = 新しい B($this);
}
関数 __destruct(){
// echo "破壊されました";
}
}

クラスB{
プライベート $a;
関数 __construct($a){
$this->a = $a;
}
関数 __destruct(){
// echo "B descturctn";
}
}

for($i=0;;$i++){
$a = 新しい A();
If($i%1000 == 0){
echomemory_get_usage()."n";
}

}

}

上記は、A オブジェクトのインスタンス a が作成されるたびに、B オブジェクトのインスタンス b を作成し、同時に b が a を参照するようにする例を構築します。各 A オブジェクトは常に B 参照によって表され、各 B オブジェクトは同時にオブジェクト A によって参照されます。これが参照サイクルの生成方法です。

このコードを php5.2 環境で実行すると、メモリ使用量が単調に増加しており、A と B のデストラクタが実行された後、メモリが使用されるまで「A/B デストラクタ」情報が出力されないことがわかります。使い果たされました、「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 オブジェクトの使用が終了し、そのクリア関数を積極的に呼び出してそのメンバー変数ノードをクリアすると、ループが中断され、メモリ リークは発生しません。


3. その他:

1) ガベージコレクションのタイミング


Php では、参照カウントが 0 の場合、メモリはすぐに解放されます。つまり、変数への循環参照がない場合、変数のスコープから出た直後にメモリが解放されます。

循環参照検出は、特定の条件が満たされたときにトリガーされるため、上記の例では、使用されるメモリに大きな変動が見られますが、gc_collect_cycles 関数を通じて循環参照検出をアクティブに実行することもできます。

2) アンパサンドの影響

変数を明示的に参照すると、そのメモリの参照カウントが増加します:

$a = "何か";

$b = &$a;

この時点ではunset($a)していますが、メモリ領域を指す$bへの参照が残っており、メモリは解放されません。

3) unset関数の影響

unset は変数をメモリ領域から切断し、メモリ領域の参照カウントを -1 減らすだけです。上記の例では、ループ本体内では $a=new A(); は行われません。 $a の参照カウントをゼロに減らします

;

4) = null 操作の影響

$a = null は、$a が指すデータ構造を直接 null にし、その参照カウントを 0 に返します。

5) スクリプト実行終了の影響

スクリプトの実行が終了すると、参照サイクルの有無に関係なく、スクリプトで使用されていたすべてのメモリが解放されます。

www.bkjia.com本当http://www.bkjia.com/PHPjc/628717.html技術記事 PHP は自動的にメモリを管理し、不要になったオブジェクトを消去します。 PHP は、単純なガベージ コレクション メカニズムである参照カウントを使用します。すべてのオブジェクトは内部にあります...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。