ホームページ  >  記事  >  バックエンド開発  >  PHP ソース コード分析 - 変数の参照カウントとコピーオンライト (参照カウントとコピーオン Wr_PHP チュートリアル)

PHP ソース コード分析 - 変数の参照カウントとコピーオンライト (参照カウントとコピーオン Wr_PHP チュートリアル)

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

PHP 構文には、参照代入と非参照代入の 2 つの代入方法があります。

$a = 1;

$b = $a // 非参照代入

;

$c = &$b; // 参照の割り当て

$a = 1;

$b = $a // 非参照代入

;

$c = &$b; // 参照の割り当て

;

表面的には、通常、次のように考えられます。「参照代入とは、2 つの変数が同じ変数 (実際には C の zval) に対応することを意味しますが、非参照代入とは、新しい変数 (zval) が直接生成され、その値が同時にコピーされます。」

この種の考え方はほとんどの場合理解できます。 (#1)

ただし、場合によっては、次のような非常に非効率的になります: (#2)

function print_arr($arr){//非参照渡し

print_r($arr)

}

$test_arr = 配列(

'a' => 'a'、

'b' => 'b'、

'c' => 'c'、

);//これは比較的大きな配列です

print_arr($test_arr);//出力を実行するために print_arr 関数が初めて呼び出されるとき

print_arr($test_arr);//出力を実行するために print_arr 関数を 2 回目に呼び出します

function print_arr($arr){//非参照渡し

print_r($arr);

}

$test_arr = 配列(

'a' => 'a',

'b' => 'b',

'C' = & gt;

...

);//これは比較的大きな配列です

print_arr($test_arr);//出力を実行するために print_arr 関数が初めて呼び出されるとき

print_arr($test_arr);//出力を実行するために print_arr 関数を 2 回目に呼び出します

上記の理解 (#1) に従って、print_arr を非参照で 2 回実行すると、$test_arr とまったく同じ新しい変数が 2 つ生成され、非常に非効率になります。

実際のコードが実行されるとき、2 つの新しい変数は生成されません。なぜなら、PHP カーネルはすでに最適化に役立っているからです。

これはどのようにして達成されるのでしょうか?ここで、この記事の要点である参照カウントとコピーオンライトについて説明します。これは、参照カウントとコピーオンライトの 2 つのメカニズムを使用して最適化されます。

これら 2 つのメカニズムを紹介する前に、まず基本的な知識、つまり PHP の変数がカーネル内でどのように表現されるかを理解しましょう。

PHP で定義された変数は zval で表されます。zval の定義は Zend/zend.h で定義されます。

typedef struct _zval_struct zval;

typedef Union _zvalue_value {

長い lval; /* 長い値 */

double dval; /* 倍精度の値 */

構造体 {

char *val

整数

HashTable *ht; /* ハッシュ テーブルの値 */

zend_object_value オブジェクト

zvalue_value

struct _zval_struct {

/* 変数情報 */

zvalue_value 値; /* 値 */

zend_uint 参照カウント

zend_uchar タイプ; /* アクティブなタイプ */

zend_uchar is_ref

};

typedef struct _zval_struct zval;

typedef Union _zvalue_value {

長い lval; /* 長い値 */

double dval; /* 倍精度の値 */

構造体{

char *val;

int len;

} str;

HashTable *ht; /* ハッシュ テーブルの値 */

zend_object_value obj;

zvalue_value;

struct _zval_struct {

/* 変数情報 */

zvalue_value 値; /* 値 */

zend_uint refcount;

zend_uchar タイプ; /* アクティブなタイプ */

zend_uchar is_ref;

};

このうち、refcount と is_ref は、参照カウントとコピーオンライトの 2 つのメカニズムを実装するための基礎です。

現在の変数 refcount には参照カウントが格納されます。これは、zval が最初に作成されたときは 1 です。参照が追加されるたびに、refcount++ が追加されます。参照分離を行う場合は、refcount-- を実行します。

is_ref は、zval が参照状態であるかどうかを示すために使用されます。 zval は初期化すると 0 になり、参照ではないことを意味します。

$a;//a:refcount=1,is_ref=0,value=NULL;

$a = 1; //a:refcount=2,is_ref=0, 値=1;

$b = $a; //a,b:refcount=3,is_ref=0,value=1;

$c = $a; //a,b,c:refcount=4,is_ref=0,value=1;

$d = &$c; //a,b:refcount=3,is_ref=0,value=1; c,d:refcount=1, is_ref=1, value=1

$a;//a:refcount=1,is_ref=0, value=NULL;

$a = 1; //a:refcount=2,is_ref=0,value=1;

$b = $a; //a,b:refcount=3,is_ref=0,value=1;

$c = $a; //a,b,c:refcount=4,is_ref=0,value=1;

$d = &$c; //a,b:refcount=3,is_ref=0,value=1; c,d:refcount=1, is_ref=1, value=1 上のコードのコメントは、これが行が実行されると、refcountとis_refが変更されます

コピーオンライト

Php 変数は、参照カウントを通じて変数の共有データを実現します。変数の 1 つの値を変更するとどうなるでしょうか。

変数を書き込もうとするときに、その変数が指す zval が複数の変数で共有されていることがわかると、Zend は ref_count が 1 の zval をコピーし、元の zval の refcount をデクリメントします。このプロセスは「zval 分離」と呼ばれます。 」。 zend は書き込み操作が発生したときにのみコピー操作を実行することがわかり、コピー オン ライト (コピー オン ライト) とも呼ばれます

参照変数の場合、参照によって割り当てられた変数は、バンドルされているすべての変数を変更する必要があります。

$a=1;

$b=$a;

$a=1;

$b=$a;実行時のメモリ構造図:

$a=1;

$b=&a;

$a=1;

$b=&a;実行時のメモリ構造図:

上記からわかるように、参照であろうと非参照であろうと、この直接代入では新しい変数は作成されません。

参照の場合のみ is_ref は 1 に設定されます。逆参照されると、is_ref は 0 に設定されます。

読み取り/書き込みレプリケーションは、変数を分離する is_ref に基づいています。

is_ref=1の場合、変数参照時に「参照中の変数分離」が行われます

$a = 1;

$b = $a;

$c = &$b;

$a = 1;

$b = $a;

$c = &$b;実行時のメモリ構造図:

is_ref=0の場合、非参照変数の場合は「非参照時の変数分離」を行う

$a = 1;

$b = &$a;

$c = $b;

$a = 1;

$b = &$a;

$c = $b;

実行時のメモリ構造図:

本当に変数の値を変更する必要がある場合にのみ、

コード (#2) をもう一度見てみると、実際には新しい変数は生成されず、$test_arr 変数が常に出力されていることがわかります。したがって、PHP で変数が参照によって渡されることはほとんどありませんが、それでもパフォーマンスの問題は発生しません。

神様のブログより抜粋


http://www.bkjia.com/PHPjc/478512.html

www.bkjia.com本当http://www.bkjia.com/PHPjc/478512.html技術記事 PHP 構文には、参照代入と非参照代入の 2 つの代入方法があります。 ?php $a = 1; $b = $a; // 非参照代入 $c = $b; // 非参照代入 $a = 1; .. .
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。