1. 程式人生 > >理解php核心的 引用計數器與寫時複製

理解php核心的 引用計數器與寫時複製

zval結構中有以下兩個成員變數用於引用計數器:
is_ref:BOOL值,標識變數是否是引用集合
refcount:計算指向引用集合的變數個數


寫時複製:就是當變數的值改變時才進行記憶體的複製。

<?php

$a = "this a test ";

xdebug_debug_zval('a');

$b = $a;

xdebug_debug_zval('a');

$a = "changed the test value";

xdebug_debug_zval('a');

執行結果:

a:

(refcount=1, is_ref=0),  (length=12)
a: 
(refcount=2, is_ref=0),  (length=12)
a: 
(refcount=1, is_ref=0)
, (length=22)
當$a的值賦給變數$b時,變數$a的refcount增加1,所以這時候變數$a跟變數$b是指向同一記憶體塊的;
改變$a的值時,發現refcount的值變回1,所有這時候變數$a和$b 指向不同的記憶體塊,這就是寫時複製。就是兩個指向同一記憶體塊的變數,當其中一個變數的發生變化,才會另外建立一個記憶體塊去儲存新的值。

寫時複製也是一種引用,只不過這種引用會受到變數值的改變而破壞罷了。

顯式引用情況:

<?php

$a = 1;

xdebug_debug_zval('a');

$b = & $a;

xdebug_debug_zval('a');

$b += 5;

xdebug_debug_zval('a');

執行結果:

a:

(refcount=1, is_ref=0), 
a: 
(refcount=2, is_ref=1), 
a: 
(refcount=2, is_ref=1), 
is_ref欄位等於1,表示此變數被引用。refcount也相應+1

在PHP核心中通過以下程式碼判斷是否複製變數:

if ((*varval->is_ref || (*varval)->refcount<2)) {

return *varval;

}

當變數被引用,或者引用計數器小於2時會直接返回變數的指標(直接返回變數的實體,而不復制變量的值)。當修改一個被引用變數的值時,所有引用他的變數其值也會被修改,因為他們指向同一個zval容器。