摘要:引用計數變量分離寫時拷貝我們一步步來理解語言特性是腳本語言,所謂腳本語言,就是說并不是獨立運行的,要運行代碼需要解析器,用戶編寫的代碼最終都會被解析器解析執行的執行是通過引擎,是用編寫的用戶編寫的代碼最終都會被翻譯成的虛擬機的虛擬指令來執行
zval、引用計數、變量分離、寫時拷貝
我們一步步來理解
1、php語言特性
PHP是腳本語言,所謂腳本語言,就是說PHP并不是獨立運行的,要運行PHP代碼需要PHP解析器,用戶編寫的PHP代碼最終都會被PHP解析器解析執行
PHP的執行是通過Zend engine(ZE, Zend引擎),ZE是用C編寫的
用戶編寫的PHP代碼最終都會被翻譯成PHP的虛擬機ZE的虛擬指令(OPCODES)來執行
也就說最終會被翻譯成一條條的指令
既然這樣,有什么結果和你預想的不一樣,查看php源碼是最直接最有效的
2、php變量的存儲結構
在PHP中,所有的變量都是用一個結構zval結構來保存的,在Zend/zend.h中可以看到zval的定義:
zval結構包括:
① value —— 值,是真正保存數據的關鍵部分,定義為一個聯合體(union)
② type —— 用來儲存變量的類型
③ is_ref —— 下面介紹
④ refcount —— 下面介紹
聲明一個變量
$addr="北京";
PHP內部都是使用zval來表示變量的,那對于上面的腳本,ZE是如何把addr和內部的zval結構聯系起來的呢?
變量都是有名字的(本例中變量名為addr)
而zval中并沒有相應的字段來體現變量名。PHP內部肯定有一個機制,來實現變量名到zval的映射
在PHP中,所有的變量都會存儲在一個數組中(確切的說是hash table)
當你創建一個變量的時候,PHP會為這個變量分配一個zval,填入相應的信息,然后將這個變量的名字和指向這個zval的指針填入一個數組中。當你獲取這個變量的時候,PHP會通過查找這個數組,取得對應的zval
注意:數組和對象這類復合類型在生成zval時,會為每個單元生成一個zval
3、我們經常說每個變量都有一個內存地址,那這個zval和變量的內存地址,這倆有什么關系嗎?
定義一個變量會開辟一塊內存,這塊內存好比一個盒子,盒子里放了zval,zval里保存了變量的相關信息,需要開辟多大的內存,是由zval所占空間大小決定的
zval是內存對象,垃圾回收的時候會把zval和內存地址(盒子)分別釋放掉
4、引用計數、變量分離、寫時拷貝
zval中的refcount和is_ref還沒有介紹,我們知道PHP是一個長時間運行的服務器端腳本。那么對于它來說,效率和資源占用率是一個很重要的衡量標準,也就是說,PHP必須盡量減少內存占用率。考慮下面這段代碼:
第一行代碼創建了一個字符串變量,申請了一個大小為9字節的內存,保存了字符串“laruence”和一個NULL(