這篇文章主要介紹了用php變數寫時複製機制,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
轉載自LYC的部落格
程式設計思想雖然可以共用,不過語言間的差異還是比較明顯的,只是使用者之間沒有意識到而己,而了解其中的差異對於編寫程式以及把握效能還是有好處的。下面我們來介紹下PHP的一個很重要的機制copy on write,我們先以最簡單的變數來介紹這個機制,在說這個之前,筆者先來介紹下弱類型是怎麼實現的。
大家都知道,PHP是由C實現的,但C是強型別語言,PHP怎麼做到弱型別語言。一起來看下,PHP變數在C語言底層的程式碼,
typedef struct _zval_struct zval; typedef unsigned int zend_uint; ypedef 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
從這個地方發現幾個重要點
所有的php變數開闢的記憶體空間都是在堆中,無論是臨時變數或全域變量,只是php的臨時變數記錄在active_symbal_table表中,全域變數記錄中symbal_table表中
php幹嘛比C慢。多做了這麼多事,能不慢嗎?
當php類似
#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; //这个才是正在重新开辟新的内存空间
相關推薦:
#以上是php變數之寫時複製機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!