PHP源碼分析-變數的引用計數、寫時複製(Reference counting & Copy-on-Wr_PHP教程

來源:互聯網
上載者:User
PHP文法中有兩種賦值方式:引用賦值、非引用賦值。

$a = 1;

$b = $a; // 非引用賦值

$c = &$b; // 引用賦值

$a = 1;

$b = $a; // 非引用賦值

$c = &$b; // 引用賦值

從表面看,通常會這樣認為:“引用賦值就是兩個變數對應同一個變數(在C中其實就是一個zval),非引用賦值則是直接產生的一個新的變數(zval),同時將值copy過來”。

這種認為在大部分情況下都是可以想通的。(#1)

但有些情況下則會顯得非常低效,例如:(#2)

function print_arr($arr){//非引用傳遞

print_r($arr);

}

$test_arr = array(

'a' => 'a',

'b' => 'b',

'c' => 'c',

...

);//這裡一個比較大的數組

print_arr($test_arr);//第一次調用print_arr函數執行輸出

print_arr($test_arr);//第二次調用print_arr函數執行輸出

function print_arr($arr){//非引用傳遞

print_r($arr);

}

$test_arr = array(

'a' => 'a',

'b' => 'b',

'c' => 'c',

...

);//這裡一個比較大的數組

print_arr($test_arr);//第一次調用print_arr函數執行輸出

print_arr($test_arr);//第二次調用print_arr函數執行輸出

如果按照上面的理解方式(#1),那麼執行兩次print_arr,並且是非引用的方式,則會產生兩個與$test_arr完全相同的新的變數,那麼將是非常低效的。

實際代碼在運行中,並不會產生兩個新的變數。因為PHP核心中已經協助我們進行了最佳化。

具體如何?的呢?這裡就要講到本文的要點:Reference counting & Copy-on-Write,正是採用引用計數、寫時複製這兩個機製得以最佳化。

在介紹這兩個機制前,先瞭解一個基本知識:PHP中的變數在核心中是如何表示的。

PHP中定義的變數都是以一個zval來表示的,zval的定義在Zend/zend.h中定義:

typedef struct _zval_struct zval;

typedef union _zvalue_value {

long lval; /* long value */

double dval; /* double value */

struct {

char *val;

int len;

} str;

HashTable *ht; /* hash table value */

zend_object_value obj;

} zvalue_value;

struct _zval_struct {

/* Variable information */

zvalue_value value; /* value */

zend_uint refcount;

zend_uchar type; /* active type */

zend_uchar is_ref;

};

typedef struct _zval_struct zval;

typedef union _zvalue_value {

long lval; /* long value */

double dval; /* double value */

struct {

char *val;

int len;

} str;

HashTable *ht; /* hash table value */

zend_object_value obj;

} zvalue_value;

struct _zval_struct {

/* Variable information */

zvalue_value value; /* value */

zend_uint refcount;

zend_uchar type; /* active type */

zend_uchar is_ref;

};

其中,refcount和is_ref就是實現引用計數、寫時複製這兩個機制的基礎。

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, 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

$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的變化.

Copy on Write

Php變數通過引用計數實現變數共用資料,那如果改變其中一個變數值呢?

當試圖寫入一個變數時,Zend若發現該變數指向的zval被多個變數共用,則為其複製一份ref_count為1的zval,並遞減原zval的refcount,這個過程稱為“zval分離”。可見,只有在有寫操作發生時zend才進行拷貝操作,因此也叫copy-on-write(寫時拷貝)

對於引用型變數,其要求和非引用型相反,引用賦值的變數間必須是捆綁的,修改一個變數就修改了所有捆綁變數。

$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中使用引用方式傳遞變數,卻仍然不會有效能問題的原因。


摘自 God's blog

http://www.bkjia.com/PHPjc/478512.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/478512.htmlTechArticlePHP文法中有兩種賦值方式:引用賦值、非引用賦值。 ?php $a = 1; $b = $a; // 非引用賦值 $c = $b; // 引用賦值 ?php $a = 1; $b = $a; // 非引用賦值 $c...

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.