国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

(PHP7內核剖析-3) 變量

RiverLi / 1817人閱讀

摘要:插入一個元素時先將元素按先后順序插入數組,位置是,再根據的哈希值映射到散列表中的某個位置,將存入這個位置查找時先在散列表中映射到,得到在數組的位置,再從數組中取出元素。目前只有兩種類型會使用這種機制。

1.變量結構

typedef struct _zval_struct     zval;

typedef union _zend_value {
    zend_long         lval;    //int整形
    double            dval;    //浮點型
    zend_string      *str;     //string字符串
    zend_array       *arr;     //array數組
    zend_object      *obj;     //object對象
    zend_resource    *res;     //resource資源類型
    zend_reference   *ref;     //引用類型,通過&$var_name定義的
} zend_value;

struct _zval_struct {
    zend_value        value; //變量實際的value
    union {
        struct {
            ZEND_ENDIAN_LOHI_4( 
                zend_uchar    type,         //變量類型
                zend_uchar    type_flags,  //類型掩碼,不同的類型會有不同的幾種屬性,內存管理會用到
                zend_uchar    const_flags,
                zend_uchar    reserved)
        } v;
        uint32_t type_info; //上面4個值的組合值,可以直接根據type_info取到4個對應位置的值
    } u1;
    union {
        uint32_t     var_flags;
        uint32_t     next;  //哈希表中解決哈希沖突時用到   
        uint32_t     cache_slot;   
        uint32_t     lineno;    
        uint32_t     num_args;    
        uint32_t     fe_pos;  
        uint32_t     fe_iter_idx;
    } u2;
};


2.變量類型

#define IS_UNDEF                    0
#define IS_NULL                     1
#define IS_FALSE                    2
#define IS_TRUE                     3
#define IS_LONG                     4
#define IS_DOUBLE                   5
#define IS_STRING                   6
#define IS_ARRAY                    7
#define IS_OBJECT                   8
#define IS_RESOURCE                 9
#define IS_REFERENCE                10
其中undef、true、false、null沒有value,直接根據type區分,而long、double的值則直接存在value中,其他類型為指針


3.字符串

typedef struct _zend_string   zend_string;

struct _zend_string {
    zend_refcounted_h gc;  //變量引用信息,比如當前value的引用數
    size_t            len;  //字符串長度,通過這個值保證二進制安全
    char              val[1]; //字符串內容,變長struct,分配時按len長度申請內存
};


4.數組

typedef struct _zend_array HashTable;
typedef struct _zend_array zend_array;

typedef struct _Bucket {
    zval              val; //存儲的具體value,這里嵌入了一個zval,而不是一個指針
    zend_ulong        h;   //哈希值
    zend_string      *key; //key值
} Bucket;

struct _zend_array {
    zend_refcounted_h gc; //引用計數信息
    uint32_t          nTableMask;  //計算bucket索引時的掩碼,用于散列表的計算nIndex
    Bucket           *arData;     //bucket數組
    uint32_t          nNumUsed;   //已用bucket數
    uint32_t          nNumOfElements; //已有元素數,nNumOfElements <= nNumUsed,因為刪除的并不是直接從arData中移除
    uint32_t          nTableSize; //數組的大小,為2^n,默認為8
    uint32_t          nInternalPointer; //數值索引,用于HashTable遍歷
    zend_long         nNextFreeElement;//下一個空閑可用位置的數字索引
    dtor_func_t       pDestructor;//析構函數,銷毀時調用的函數指針
};
HashTable主要依賴arData實現元素的存儲、索引。插入一個元素時先將元素按先后順序插入Bucket數組,位置是idx,再根據key的哈希值映射到散列表中的某個位置nIndex,將idx存入這個位置;查找時先在散列表中映射到nIndex,得到value在Bucket數組的位置idx,再從Bucket數組中取出元素。
$arr["a"] = 1;
$arr["b"] = 2;
$arr["c"] = 3;
$arr["d"] = 4;

unset($arr["c"]);

哈希碰撞:當出現沖突時將原value的位置保存到新value的zval.u2.next中,然后將新value代替原value位置
擴容:PHP散列表的大小為2^n,插入時如果容量不夠則首先檢查已刪除元素所占比例,如果達到閾值,則將已刪除元素移除,重建索引,如果未到閾值則進行擴容操作,擴大為當前大小的2倍,將當前Bucket數組復制到新的空間,然后重建索引。
重建散列表:當刪除元素達到一定數量或擴容后都需要重建散列表,因為value在Bucket位置移動了或哈希數組nTableSize變化了導致key與value的映射關系改變,重建過程實際就是遍歷Bucket數組中的value,然后重新計算映射值更新到散列表,移除已刪除的value,將后面未刪除的value依次前移


5.引用

引用是PHP中比較特殊的一種類型,它實際是指向另外一個PHP變量,對它的修改會直接改動實際指向的zval,可以簡單的理解為C中的指針,在PHP中通過&操作符產生一個引用變量,也就是說不管以前的類型是什么,&首先會創建一個zend_reference結構,其內嵌了一個zval,這個zval的value指向原來zval的value(如果是布爾、整形、浮點則直接復制原來的值),然后將原zval的類型修改為IS_REFERENCE,原zval的value指向新創建的zend_reference結構。
typedef struct _zend_reference  zend_reference;

struct _zend_reference {
    zend_refcounted_h gc;
    zval              val;
};


6.引用計數

typedef struct _zend_refcounted_h {
    uint32_t         refcount;         
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    type,
                zend_uchar    flags,   
                uint16_t      gc_info)  
        } v;
        uint32_t type_info;
    } u;
} zend_refcounted_h;
$a = "time:" . time();   //$a       ->  zend_string_1(refcount=1)
$b = $a;                 //$a,$b    ->  zend_string_1(refcount=2)
$c = $b;                 //$a,$b,$c ->  zend_string_1(refcount=3)

unset($b);               //$b = IS_UNDEF  $a,$c ->  zend_string_1(refcount=2)
并不是所有的數據類型都會用到引用計數,long、double直接都是硬拷貝,只有value是指針的那幾種類型(除interned string,immutable array)才能用到引用計數。可由zval.u1.type_flag判斷


7.寫時復制

$a = array(1,2);
$b = &$a;
$c = $a;

//發生分離
$b[] = 3;

事實上只有string、array兩種支持,


8.垃圾回收

PHP變量的回收主要有兩種:主動銷毀、自動銷毀。主動銷毀指的就是 unset ,而自動銷毀就是PHP的自動管理機制,在return時減掉局部變量的refcount,即使沒有顯式的return,PHP也會自動給加上這個操作,另外一個就是寫時復制時會斷開原來value的指向,這時候也會檢查斷開后舊value的refcount。
$a = [1];
$a[] = &$a;

unset($a);

unset($a)之前引用關系:

unset($a)之后:

可以看到,unset($a)之后由于數組中有子元素指向$a,所以refcount > 0,無法通過簡單的gc機制回收,這種變量就是垃圾,垃圾回收器要處理的就是這種情況,目前垃圾只會出現在array、object兩種類型中,所以只會針對這兩種情況作特殊處理:當銷毀一個變量時,如果發現減掉refcount后仍然大于0,且類型是IS_ARRAY、IS_OBJECT則將此value放入gc可能垃圾雙向鏈表中,等這個鏈表達到一定數量后啟動檢查程序將所有變量檢查一遍,如果確定是垃圾則銷毀釋放。
目前只有object、array兩種類型會使用這種機制。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/28543.html

相關文章

  • (PHP7內核剖析-4) 局部變量,全局變量,常量

    摘要:局部變量中局部變量分配在結構上,每次執行都會生成一個新的,局部變量在執行之初分配,然后在執行結束時釋放,這是局部變量的生命周期。 1.局部變量 PHP中局部變量分配在zend_execute_data結構上,每次執行zend_op_array都會生成一個新的zend_execute_data,局部變量在執行之初分配,然后在執行結束時釋放,這是局部變量的生命周期。 讀寫操作:局部變量通過...

    yagami 評論0 收藏0
  • (PHP7內核剖析-5) PHP代碼的編譯

    摘要:代碼的編譯的解析過程任務就是將代碼轉化為數組,代碼里的所有信息都保存在數組中,然后將數組交給引擎執行,就是內核具體執行的命令,比如賦值加減操作函數調用等,每一條都對應一個處理,這些是提前定義好的函數。 1.PHP代碼的編譯 PHP的解析過程任務就是將PHP代碼轉化為opcode數組,代碼里的所有信息都保存在opcode數組中,然后將opcode數組交給zend引擎執行,opcode就是...

    DevTTL 評論0 收藏0
  • (PHP7內核剖析-10) 線程安全

    摘要:中專門為解決線程安全的問題抽象出了一個線程安全資源管理器,實現原理比較簡單既然共用資源這么困難那么就干脆不共用,各線程不再共享同一份全局變量,而是各復制一份,使用數據時各線程各取自己的副本,互不干擾。 1.線程安全資源管理器 PHP的SAPI多數是單線程環境,比如cli、fpm、cgi,每個進程只啟動一個主線程,這種模式下是不存在線程安全問題的,但是也有多線程的環境,比如Apache,...

    Achilles 評論0 收藏0
  • (PHP7內核剖析-7) Zend引擎執行過程

    1.EG(executor_globals/zend_executor_globals) PHP整個生命周期中最主要的一個結構,是一個全局變量,在main執行前分配(非ZTS下),直到PHP退出,它記錄著當前請求全部的信息 showImg(https://segmentfault.com/img/bV8fW0?w=960&h=777); 2.EX(execute_data/zend_execut...

    elisa.yang 評論0 收藏0
  • (PHP7內核剖析-6) 函數

    摘要:引擎中定義了很多內部函數供用戶在中使用,比如等等,除了引擎中定義的內部函數,擴展中也提供了大量內部函數,我們也可以靈活的通過擴展自行定制。頭部是一個與完全相同的結構函數指針,展開 1.函數的存儲結構 typedef union _zend_function zend_function; union _zend_function { zend_uchar typ...

    crelaber 評論0 收藏0

發表評論

0條評論

RiverLi

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<