コンセプト
ガベージコレクションのメカニズムは、それが自動的にプログラムの割り当てられたメモリブロックは、もはや使用されているリリースしません、動的に割り当てられたメモリ方式です。
ガベージコレクションのメカニズムが可能に プログラマがする ビジネスロジックに多くのエネルギーを置くメモリ割当プログラムに関する過度に心配するではありません。概念に関連付けられている、メモリリークがプログラムがメモリの無駄が生じ、使用されなくなっているメモリを解放するために失敗しないことを意味します。
だから、PHPのガベージコレクションのメカニズムは、それを達成する方法ですか?
内部ストレージ構造のPHP変数
最初に理解する必要があることである基礎ガベージコレクタの内容の原理の理解を容易にするためには、。
PHP すべてのタイプの変数の底部にあるのzval構造の形で実装(ソースコードファイルのZend / zend.h)
ソースルートディレクトリ検索
grep -rin --color --include=*.h --include=*.c _zval_struct *
struct _zval_struct {
/* Variable information */
zvalue_value value; /* 变量value值 */
zend_uint refcount__gc; /* 引用计数内存中使用次数,为0删除该变量 */
zend_uchar type; /* 变量类型 */
zend_uchar is_ref__gc; /* 区分是否是引用变量,是引用为1,否则为0 */
};
新しいガベージコレクションのメカニズムのない導入、すなわち存在しないため、上記のzval構造はPHP5.3前に、PHP5.3バージョン後の構造である:注意しないGCは、そう何という名前の_gc
、しかし、パフォーマンスの問題が原因PHP7バージョンの後ので、ここにzval構造を書き換えもはや発現しませんでした。
参照カウント原理
変数コンテナ
それぞれ呼ばれるPHPの変数に格納されたzvalを変数コンテナ。可変コンテナを作成する際に、容器変数ref_count初期値1は、各変数の後に使用されるref_count + 1。あなたは(変数を削除する場合)(未設定)、それは変数コンテナを指す1 - ref_count。
非配列やオブジェクト変数
変数に割り当てられた各時定数は、必要があります変数コンテナを
例えば:
$a = 'new string';
xdebug_debug_zval('a');
結果が出力されます。
a:(refcount=1, is_ref=0),string 'new string' (length=10)
配列とオブジェクト変数
たびに変数の定数値は、必要があります要素の数+1にzvalを
例えば:
$b = [
'name' => 'new string',
'number' => 12
];
xdebug_debug_zval('b');
結果が出力されます。
b:
(refcount=1, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
'number' => (refcount=1, is_ref=0),int 12
割り当て原理
コピー・オン・ライトの原則
設計のPHPは、二つの変数の同じ値に対する変数間の代入は、メモリが共有されるように、メモリを節約するために、つまり、であろうグローバルシンボルテーブルの変数b内の可変ポインタポイント変数へのポイントzvalを同じ構造だけにzval構造における変数の変更は、変数コンテナのメモリコピーが発生する変更されますので、呼び出されたコピー・オン・ライト原則。
原則としてコピー・オン・ライト トリガのタイミングを:
変数を変更するときに参照カウント> 1の場合、PHP、変数が発見され、容器は可変メモリコピーを実行します
例えば:
// 创建一个变量容器,变量 a 指向给变量容器,a 的 ref_count 为 1
$a = ['name' => 'string','number' => 3];
// 变量 b 也指向变量 a 指向的变量容器,a 和 b 的 ref_count 为 2
$b = $a;
xdebug_debug_zval('a', 'b');
echo '<hr/>'
// 变量 b 的其中一个元素发生改变,此时会复制出一个新的变量容器,变量 b 重新指向新的变量容器,a 和 b 的ref_count 变成 1
$b['name'] = 'new string';
xdebug_debug_zval('a', 'b');
出力結果:
a:(refcount=2, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=1, is_ref=0),int 3
b:(refcount=2, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=1, is_ref=0),int 3
________________________________________________________________________________________
a:(refcount=1, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=2, is_ref=0),int 3
b:(refcount=1, is_ref=0),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
'number' => (refcount=2, is_ref=0),int 3
書き込み時に原則を変更
彼は普通の割り当ての場合は、その割り当てはそれを参照するとしていますか?
最初の説明のために
$a = ['name' => 'string','number' => 3];
$b = &$a;
xdebug_debug_zval("a", "b");
結果出力
a:(refcount=2, is_ref=1),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=1, is_ref=0),int 3
b:(refcount=2, is_ref=1),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'string' (length=6)
'number' => (refcount=1, is_ref=0),int 3
この時点で、我々は、変数aおよびb参照カウントまたは2を見つけるが、1 is_refなるis_refなり、変数bに割り当てられた参照変数は、変数が元の容器に変更されている場合ので、それは1、および参照カウント+ 1
参照に基づいてその割り当て、彼らはそれの変数を変更した場合?
$a = ['name' => 'string','number' => 3];
$b = &$a;
$b['name'] = "new string";
xdebug_debug_zval("a", "b");
出力結果:
a:(refcount=2, is_ref=1),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
'number' => (refcount=1, is_ref=0),int 3
b:(refcount=2, is_ref=1),
array (size=2)
'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
'number' => (refcount=1, is_ref=0),int 3
驚くべきことが起こったトリガーがあるため、変数の値の変化変数bと、実際には、そこにいた書き込み原理を変更します。
原則書き込み変更 トリガタイミングを:
変数コンテナ1 is_ref変数is_ref優先チェックコンテナを割り当てられる前に、コピー・オン・ライトが行われますが、元の変数に基づいて、コンテナの中身を作るように変更されていない場合は、1に等しいです。 is_ref変数容器1に割り当てられた他の変数ならば、それはすぐにトリガするチェンジの書き込み原理を
上記の例を組み合わせた今、それは次のようになりますか?
$a = ['name' => 'string','number' => 3];
$b = $a;
$c = &$a;
xdebug_debug_zval("a", "b", "c");
出力結果:
実装プロセス:
最初の行を実行する:参照カウントが可変コンテナであります
参照カウント変数容器2、変数aおよびbを共有同じ変数コンテナ:第二行を実行します
三行目の実装:変化が発生している場合、トリガする、変数cに割り当てられた変数は、この時間可変容器参照カウント> 1を参照するコピーオンライトを、変数aおよびbの分離は、その変数を参照に割り当てられていますC変数は、変数is_rel容器は1となり、2は参照カウントとなります。
0に参照カウント
コンテナが可変である場合にはref_countは、変数コンテナはメモリの回復を達成するために破壊されることを示し、0にカウントされます。
これは、PHP 5.3のバージョンにガベージコレクションの前。
例えば:
$a = "new string";
$b = $a;
xdebug_debug_zval('a');
unset($b); // 删除了符号表中的变量名 b,同时它指向的变量容器 ref_count -1
xdebug_debug_zval('a');
xdebug_debug_zval('b');
出力結果:
a:(refcount=2, is_ref=0),string 'new string' (length=10)
a:(refcount=1, is_ref=0),string 'new string' (length=10)
b: no such symbol
によって引き起こされる循環参照のメモリリーク
我々はこの配列またはオブジェクトの要素として配列またはオブジェクトを追加すると、この時間は可変記号(未設定)を削除した場合、この変数コンテナは削除されません。その子の要素はまだ変数コンテナを指しているが、理由はすべてのスコープの変数コンテナを指している兆候なし、そのためユーザーは、この変数コンテナをクリアする方法はありません、結果はスクリプトの実行パッシブ明確にこの変数コンテナの終わりまで、メモリリークにつながります。
たとえば:要素としての配列は、あなたに追加します
$a = array( 'one' );
$a[] = &$a;
xdebug_debug_zval( 'a' );
出力:
a:
(refcount=2, is_ref=1),
array (size=2)
0 => (refcount=1, is_ref=0),string 'one' (length=3)
1 => (refcount=2, is_ref=1),&array<
アイコン:
配列変数を参照するAはまた、アレイの第二の要素である「1」変数コンテナが指摘参照カウントがある2。上記の出力&アレイ<手段は、元の配列に向けられています。
ただ、変数の設定解除のための呼び出しのように記号を削除し、それが指す被引用数の変数コンテナはまた、1だけ減少します。我々は上記のコードを実行しているのであれば、変数コール設定解除は、変数Aと変数配列要素コンテナが「1」の引用から1を減算する指さ2となる1次の例で示すことができます:
unset($a);
アイコン:
上記の状況は何もダウンだけ一度か二度発生しますが、メモリリークが明らかに大きな問題である、発生した何千回もあれば、何百何千回の場合。このような問題は、多くの場合、このような要求にデーモン(のデーモン)は、基本的に終了していない又は大きな単位テストスイート(セット)として、長時間実行されるスクリプトで発生します。
新しいガベージコレクション
PHP 5.3のバージョンは、後に導入されたルートバッファリング機構、ルートバッファのデフォルト設定指定された数のzvalすなわちPHPが開始されます(デフォルト10000)、PHPの存在する場合、それが発見された循環参照は zvalをは、バッファにそのルーツを置く際に、ときルートバッファは(デフォルトは10000です)番号指定した設定ファイルに到達した後、循環参照によって引き起こされるメモリリークを解決するために、ガベージコレクションを実行します。
ガベージコレクションのアルゴリズム
ルートバッファがいっぱいになるたびに、PHPは、血管の横断ができるすべての変数のルートバッファリングする削除シミュレートし、その後、回復をシミュレートします。しかし、PHPは、シミュレーションのみの後に削除されます変数コンテナ回復の参照カウント> 0、そして何の回復はありません参照カウント= 0でのゴミです。
ごみの基準として認識
1、参照カウントがコンテナ変数がクリアされ、ゼロ、(フリー)に還元されている場合ではなく、スパム
基準はzvalをさらにカウントが0より大きい場合にデクリメント2、それは、ガベージにサイクルします。次に、ごみの期間において、基準カウント数を1だけデクリメントし、その容器の検査基準変数がごみである部品を見つけるために、ゼロであるかどうかをチェックすることにより。
概要
ガベージコレクション:
1 PHPへの参照カウントメカニズム(機構以前のみPHP5.3)に基づいて、
図2に示すように、ルートバッファ機構ながら、円形のPHPはルートに入れますzvalを参照し、検索がある場合バッファ、ルート番号指定された構成ファイルに到達したとき、それはゴミ収集される緩衝液は、循環参照によって引き起こされるメモリリークを解決するために、(PHP5.3機構を導入し始めました)