実装手順
1. オブジェクトに参照カウンタを追加します。参照カウンタの値は、毎回どこかで増加します。参照が無効になるたびに、カウンタは 1 ずつ減らされます。
変数値の refcount が 1 減らされて 0 になった場合、その値は解放され、ガベージではなくなります。ガベージ コレクターはそれを処理しません。
変数値の refcount が 1 減らされた後に 0 より大きい場合、その値は解放不可能とみなされ、ガベージになる可能性があります。
2. ガベージ コレクタは、可能性のあるガベージを収集し、一定量に達すると、ガベージ識別プログラムを起動し、実際のガベージを解放します。
例
<?php // PHP ガベージ コレクション メカニズムの場合: PHP マニュアルを参照 //---------------------スカラー型--------------------- // ヒント: 各 PHP 変数は、「zval」と呼ばれる変数コンテナーに存在します。このコンテナーには、変数の型と値が含まれます。「is_ref」: 参照変数かどうか、「refcount」: 参照カウント // 例: 新しい zval コンテナを生成 $a = 'new string'; // 例: zval コンテナ情報を表示 xdebug_debug_zval('a'); // a: (refcount=1, is_ref=0),string 'new string' (length=10) // 例: zval コンテナの参照数を増やす $c = $b = $a; xdebug_debug_zval('a'); // a:(refcount=3, is_ref=0),string '新しい文字列' (長さ=10) xdebug_debug_zval('b'); // b:(refcount=3, is_ref=0),string '新しい文字列' (長さ=10) xdebug_debug_zval('c'); // c:(refcount=3, is_ref=0),string '新しい文字列' (長さ=10) // ヒント: 現時点では、コンテナは 1 つだけです。PHP は生成された変数コンテナを必要のないときにコピーしないためです。 // 現時点では、この変数コンテナは変数 a、変数 b、および変数 c に関連付けられています。 unset($b); // 例: 参照カウントを減らす xdebug_debug_zval('a'); // a:(refcount=2, is_ref=0),string 'new string' (length=10) // ヒント: unset 変数を削除すると、refcount 変数のカウントが 1 つ減ります。このとき、$a と $b のみが変数コンテナーを指します。 設定を解除($a); 設定を解除($c); var_dump($a); // ヒント: このとき、recount は 0 となり、変数は削除されます。 // recount が 0 になると、型と値を含む変数コンテナがメモリから削除されます。 //---------------------複合型--------------- echo '--------------複合タイプ-----------<br/>'; $a = 配列( '名前' => 'ジュニア'、 「年齢」 => 18 ); xdebug_debug_zval('a'); // a:(refcount=1, is_ref=0), // 配列 (サイズ=2) // 'name' => (refcount=1, is_ref=0),string 'junior' (length=6) // '年齢' => (refcount=1, is_ref=0),int 18 // 例: 既存の要素を配列に追加 $a['love'] = $a['name']; xdebug_debug_zval('a'); // a:(refcount=1, is_ref=0), // 配列 (サイズ=3) // 'name' => (refcount=2, is_ref=0),string 'junior' (length=6) // '年齢' => (refcount=1, is_ref=0),int 18 // 'love' => (refcount=2, is_ref=0),string 'junior' (length=6) // $a = array('one'); // xdebug_debug_zval('a'); // // $b = &$a; // $c = $a; // $b = &$c; // xdebug_debug_zval('b'); // xdebug_debug_zval('c'); // xdebug_debug_zval('a'); // 変数コンテナの問題をクリーンアップ echo '----------メモリ リークの問題-----------<br/>'; $a = 配列('one'); xdebug_debug_zval('a'); // a:(refcount=1, is_ref=0), // 配列 (サイズ=1) // 0 => (refcount=1, is_ref=0),string 'one' (length=3) $a[] = &$a; xdebug_debug_zval('a'); // a:(refcount=2, is_ref=1), // 配列 (サイズ=2) // 0 => (refcount=1, is_ref=0),string 'one' (length=3) // 1 => (refcount=2, is_ref=1), // &配列 // unset($a); // (refcount=1, is_ref=1)=array ( // 0 => (refcount=1, is_ref=0)='one', // 1 => (refcount=1, is_ref=1)=... //) // ヒント: unset($a) の後、この構造体 (つまり、変数コンテナー) を指すスコープ内にシンボルがなくなっても、参照カウントは 1 つ減ります。 // 配列要素 "1" は依然として配列自体を指しているため、このコンテナはクリアできません // 他にそれを指しているシンボルがないため、ユーザーはこの構造をクリアする方法がなく、メモリ リークが発生します // 幸いなことに, PHP は、このデータ構造はスクリプトの実行の最後にクリアされますが、PHP がクリアする前に大量のメモリが消費されます。 // 同じことがオブジェクトでも発生します。実際、オブジェクトは常に暗黙的に参照されるため、オブジェクトで発生する可能性が高くなります。
上記は、PHP の参照カウントがガベージ コレクションを実装する方法です。皆さんの参考になれば幸いです。