PHP における参照カウントとは何を意味しますか?

醉折花枝作酒筹
リリース: 2023-03-09 13:28:01
転載
1774 人が閲覧しました

この記事では、PHP の参照カウントについて紹介します。一定の参考値があるので、困っている友達が参考になれば幸いです。

PHP における参照カウントとは何を意味しますか?

参照カウントとは

PHP のデータ構造では、参照カウントは各変数を参照し、その型と値を保存するだけでなく、2 つの変数も保存します。追加の内容は、1 つは変数が現在参照されているかどうか、もう 1 つは参照の数です。なぜさらに 2 つのコンテンツを保存する必要があるのでしょうか?もちろんガベージコレクション(GC)用です。

つまり、参照数が 0 の場合、この変数は使用されなくなり、GC を通じてリサイクルして占有されているメモリ リソースを解放できます。

どんなプログラムもメモリ リソースを無限に占有することはできません。過度のメモリ使用は、多くの場合、メモリ リークという深刻な問題につながります。GC は、メモリ処理を自動的に完了する PHP の最下層です。代わりに破壊します。 Cのように手動で解放する必要があります。

参照カウントを確認するにはどうすればよいですか?

xdebug 拡張機能をインストールし、xdebug_debug_zval() 関数を使用して、次のような指定されたメモリの詳細情報を確認する必要があります。

$a = "I am a String";
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=0)='I am a String'
ログイン後にコピー

上記のことからわかるように、この $a 変数 内容は I am a String のような文字列です。括弧内の refcount は参照の数で、is_ref は変数が参照されているかどうかを示します。これら 2 つのパラメータが変数の割り当てによってどのように変化するかを見てみましょう。

$b = $a;
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=0)='I am a String'

$b = &$a;
xdebug_debug_zval('a');
// a: (refcount=2, is_ref=1)='I am a String'
ログイン後にコピー

通常の代入を行うとrefcountとis_refは変化しませんが、参照代入を行うとrefcountが2、is_refが1になることがわかります。これは、現在の \$a 変数が参照によって割り当てられ、そのメモリ シンボル テーブルが 2 つの変数 $a と $b に使用されることを意味します。

$c = &$a;
xdebug_debug_zval('a');
// a: (refcount=3, is_ref=1)='I am a String'

unset($c, $b);
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=1)='I am a String'

$b = &$a;
$c = &$a;
$b = "I am a String new";
xdebug_debug_zval('a');
// a: (refcount=3, is_ref=1)='I am a String new'

unset($a);
xdebug_debug_zval('a');
// a: no such symbol
ログイン後にコピー

$c への参照割り当ての追加を続けると、refcount が増加し続けることがわかります。 $b と $c の設定を解除すると、refcount は 1 に戻ります。ただし、is_ref は 1 のままであることに注意してください。つまり、この変数が参照されている場合、参照された変数が Even であっても、is_ref は 1 になります。設定が解除されている場合、値は変更されません。

最後に $a の設定を解除すると、そのようなシンボルは表示されません。現在の変数は破棄されており、シンボリック参照として使用できません。 (PHP の変数は実際のメモリ アドレスではなく、メモリのシンボル テーブルに対応することに注意してください)

オブジェクト参照カウント

# は通常の型変数と同じであり、オブジェクト変数は、同様に、カウントルールも同様です。

// 对象引用计数
class A{

}
$objA = new A();
xdebug_debug_zval('objA');
// objA: (refcount=1, is_ref=0)=class A {  }

$objB = $objA;
xdebug_debug_zval('objA');
// objA: (refcount=2, is_ref=0)=class A {  }

$objC = $objA;
xdebug_debug_zval('objA');
// objA: (refcount=3, is_ref=0)=class A {  }

unset($objB);
class C{

}
$objC = new C;
xdebug_debug_zval('objA');
// objA: (refcount=1, is_ref=0)=class A {  }
ログイン後にコピー

ただし、オブジェクトのシンボル テーブルは確立された接続であることに注意してください。つまり、$objC を再インスタンス化するか、$objC を NULL に変更しても、$objA の内容には影響しません。知識に関すること: 前回のオブジェクトの割り当ては PHP の参照ですか?記事で解説してあります。オブジェクトに対する通常の代入操作も、参照型のシンボル テーブルの代入であるため、& シンボルを追加する必要はありません。

配列の参照カウント

// 数组引用计数
$arrA = [
    'a'=>1,
    'b'=>2,
];
xdebug_debug_zval('arrA');
// arrA: (refcount=2, is_ref=0)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2
// )

$arrB = $arrA;
$arrC = $arrA;
xdebug_debug_zval('arrA');
// arrA: (refcount=4, is_ref=0)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2
// )

unset($arrB);
$arrC = ['c'=>3];
xdebug_debug_zval('arrA');
// arrA: (refcount=2, is_ref=0)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2
// )

// 添加一个已经存在的元素
$arrA['c'] = &$arrA['a'];
xdebug_debug_zval('arrA');
// arrA: (refcount=1, is_ref=0)=array (
//     'a' => (refcount=2, is_ref=1)=1, 
//     'b' => (refcount=0, is_ref=0)=2, 
//     'c' => (refcount=2, is_ref=1)=1
// )
ログイン後にコピー

配列をデバッグすると、2 つの興味深いことがわかります。

まず、配列内の各要素には独自の個別の参照カウントがあります。これも理解しやすいですが、配列の各要素は個別の変数とみなすことができますが、配列はこれらの変数のハッシュの集合です。オブジェクト内にメンバ変数がある場合も同様の影響があります。配列内の要素が & によって別の変数に割り当てられると、配列全体の refcount に影響を与えることなく、この要素の refcount が増加します。

2 つ目は、配列のデフォルトの refcount が 2 であることです。実はこれはPHP7以降の新機能で、配列を定義して初期化すると、その配列は不変配列(immutable array)に変換されます。通常の配列と区別するために、この配列の refcount は 2 から始まります。この配列内の要素を変更すると、配列は通常の配列に戻ります。つまり、refcount は 1 に戻ります。なぜこのようになっているのかについては、公式には効率化のためと説明されていますが、具体的な原理については、PHP7 のソースコードを詳しく調べる必要があるかもしれません。

メモリ リークに関する注意事項

実際、PHP は最下層の GC メカニズムをすでに支援しているため、破棄と解放についてあまり心配する必要はありません。ただし、これには注意する必要があります。オブジェクトまたは配列内の要素は、それ自体に代入できます。つまり、それ自体への参照を要素に代入すると、循環参照になります。したがって、このオブジェクトは基本的に GC によって自動的に破棄される可能性は低くなります。

// 对象循环引用
class D{
    public $d;
}
$d = new D;
$d->d = $d;
xdebug_debug_zval('d');
// d: (refcount=2, is_ref=0)=class D { 
//     public $d = (refcount=2, is_ref=0)=... 
// }

// 数组循环引用
$arrA['arrA'] = &$arrA;
xdebug_debug_zval('arrA');
// arrA: (refcount=2, is_ref=1)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2, 
//     'arrA' => (refcount=2, is_ref=1)=...
// )
ログイン後にコピー

オブジェクトであっても配列であっても、印刷中やデバッグ中に... のような省略記号が表示される場合は、プログラム内に循環参照があることになります。前回のPHPにおけるオブジェクトのコピーの記事でもこの循環参照の問題について触れましたので、この問題は日々の開発において常に注意を払うべき問題となります。

推奨学習: php ビデオ チュートリアル

以上がPHP における参照カウントとは何を意味しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:csdn.net
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート