php變量之寫時復制機制(copy on write)


     編程思想雖然可以共用,不過語言間的差異還是比較明顯的,只是使用者之間沒有意識到而己,而了解其中的差異對於編寫程序以及把握性能還是有好處的。下面我們來介紹下PHP的一個很重要的機制copy on write,我們先以最簡單的變量來介紹這個機制,在說這個之前,筆者先來介紹下弱類型是怎么實現的。

 

     大家都知道,PHP是由C實現的,可是C是強類型語言,PHP怎么做到弱類型語言。一起來看下,PHP變量在C語言底層中的代碼,

    

typedef struct _zval_struct zval;
typedef unsigned int zend_uint;
typedef unsigned char zend_uchar;

struct _zval_struct {
    zvalue_value value;      /*注意這里,這個里面存的才是變量的值*/
    zend_uint refcount__gc;  /*引用計數*/
    zend_uchar type;        /* 變量當前的數據類型 */
    zend_uchar is_ref__gc;   /*變量是否引用*/
};



typedef union _zvalue_value {
    long lval;      /*PHP中整型的值*/
    double dval;    /*PHP的浮點數值*/
    struct {      
        char *val;
        int len;
    } str;               /*PHP的字符串*/
    HashTable *ht;     /*數組*/
    zend_object_value obj;  /*對象*/
} zvalue_value;

  本人加了點注釋,大家可以發現,實際上我們在PHP用的變量,低層是一個結構體zval,里面的zvalue_value結構體實際上是個聯合體,這個聯合體才是實際存放着PHP的變量值,下面我們以實際的PHP代碼例子來表示整個工作過程,注意上面的引用計數。先來看C語言的,首先是非函數部分,函數部分下一章節來講

       

int i = 4;  //alloca方式在內存中分配空間,這個變量在內存中的棧區
int j = i;   //alloca方式在內存中分配空間,並且將原先內存空間里面的數據復制到新的內存空間中,這個變量在內存的棧區
int j = 5;  //不分配內存空間,對變量j所在的棧區空間的數據進行修改

 

來看PHP部分的

$i = 4;   //內核創建一個zval指針,並且為其以堆的方式開辟空間,讓指針指向這個空間,將zval中的成員引用計數置為1,類型標記為整形,並且申請一個zvalue_value指針,同樣以堆的方式以其開辟空間,同時將該聯合體中的lval賦值為4,並且在symbal_table的hash表中記錄變量i和zval指針的映射關系
$j = $i;   //沒有在申請內存空間,在zval的成員中引用計數標記為2
$j = 5;   //內核重新創建zval指針,重復下上面的步驟,我就不重復說明了,重點是將舊的zval引用計數標記為1

 

    從這個地方發現幾個重要點

1.所有的php變量開辟的內存空間都是在堆中,無論是臨時變量還是全局變量,只是php的臨時變量記錄在active_symbal_table表中,全局變量記錄中symbal_table表中

2.php干嘛比C慢。多做了這么多事,能不慢嗎?

3.當php類似$j = $i這種變量賦值時,是沒有內存開銷的,也就是你賦值個幾萬個,也只是引用計數變成幾萬而己,這個和C語言是不一樣的。而當變量的值發生變化時,才會進行重新開辟內存空間,這個機制我們稱為寫時復制機制

 

額外細節部分,當php內核發現,int的數值溢出時,也就是超出整型的范圍時,自動轉換為float,有興趣的讀者可以自己寫個很大的整型,但是不能超出float取值范圍,看看var_dump數據類型是什么。

 

最后部分:

php對象部分因為默認是引用方式的,所以就是賦值完,再改變對象的成員變量,也不會啟用寫時復制的,如以下

class Test {
     public $var = 999;
}

$test1 = new Test();
$test2 = $test1;  //只是引用計數加1而己,沒有開辟新的內存空間
$test2->var = 1000;


echo $test1->var;  //此時的值也為1000

$test3 = clone $test1;  //這個才是正在重新開辟新的內存空間

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM