成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

PHP7擴(kuò)展開發(fā)(四):拷貝與引用

PingCAP / 1000人閱讀

摘要:如果,且僅僅是如果,引用計(jì)數(shù)變成了,引擎會銷毀該。的結(jié)構(gòu)重新定義了,都有一個同樣的頭用來存儲引用計(jì)數(shù)拷貝引用有兩種方法引用。需要使用指針的復(fù)雜類型比如字符串?dāng)?shù)組和對象會自己存儲引用計(jì)數(shù)。

引用計(jì)數(shù)

迄今為止,我們向HashTables中加入的zval要么是新建的,要么是剛拷貝的。它們都是獨(dú)立的,只占用自己的資源且只存在于某個HashTable中。作為一個語言設(shè)計(jì)的概念,創(chuàng)建和拷貝變量的方法是“很好”的,但是習(xí)慣了C程序設(shè)計(jì)就會知道,通過避免拷貝大塊的數(shù)據(jù)(除非絕對必須)來節(jié)約內(nèi)存和CPU時(shí)間并不少見。考慮這段用戶代碼:


如果執(zhí)行zval_copy_ctor()(將會對字符串內(nèi)容執(zhí)行estrndup())將$a拷貝給$b,那么這個簡短的腳本實(shí)際會用掉8M內(nèi)存來存儲同一4M文件的兩份相同的副本。在最后一步取消$a只會更糟,因?yàn)樵甲址籩free()了。用C做這個將會很簡單,大概是這樣:b = a; a = NULL;。

Zend引擎的做法更聰明。當(dāng)創(chuàng)建$a時(shí),會創(chuàng)建一個潛在的string類型的zval,它含有日至文件的內(nèi)容。這個zval通過調(diào)用zend_hash_add()被
賦給$a變量。當(dāng)$a被拷貝給$b,引擎做類似下面的事情:

{
    zval **value;
    zend_hash_find(EG(active_symbol_table), "a", sizeof("a"), (void**)&value);
    ZVAL_ADDREF(*value);
    zend_hash_add(EG(active_symbol_table), "b", sizeof("b"),  value,sizeof(zval*));
}

實(shí)際代碼會更復(fù)雜點(diǎn),簡單的說,就是通過引用計(jì)數(shù)來記錄zval在符號表中、數(shù)組中、或其他地方被引用的次數(shù)。這樣$b = $a賦值只要將其引用計(jì)數(shù)+1,而不用去進(jìn)行內(nèi)容拷貝。

當(dāng)用戶空間代碼調(diào)用unset($a),引擎對該變量執(zhí)行zval_ptr_dtor()。在前面用到的zval_ptr_dtor()中,你看不到的事實(shí)是,這個調(diào)用沒有必要銷毀該zval和它的內(nèi)容。實(shí)際工作是減少refcount。如果,且僅僅是如果,引用計(jì)數(shù)變成了0,Zend引擎會銷毀該zval。

有些簡單數(shù)據(jù)類型不需要多帶帶分配內(nèi)存,也不需要計(jì)數(shù);PHP7中zval的long和double類型是 不需要 引用計(jì)數(shù)的。

php7的zval結(jié)構(gòu)重新定義了,都有一個同樣的頭(zend_refcounted)用來存儲引用計(jì)數(shù):

typedef struct _zend_refcounted_h {
    uint32_t         refcount;          /* reference counter 32-bit */
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    type,
                zend_uchar    flags,    /* used for strings & objects */
                uint16_t      gc_info)  /* keeps GC root number (or 0) and color */
        } v;
        uint32_t type_info;
    } u;
} zend_refcounted_h;
拷貝 vs 引用

有兩種方法引用zval。第一種,如上文示范的,被稱為寫復(fù)制引用(copy-on-write referencing)。第二種形式是完全引用(full referencing);當(dāng)說起“引用”時(shí),用戶空間代碼的編寫者更熟悉這種, 以用戶空間代碼的形式出現(xiàn)類似于:$a = &$b;

在zval中,這兩種類型的區(qū)別在于它的is_ref成員的值,0表示寫復(fù)制引用,非0表示完全引用。注意,一個zval不可能同時(shí)具有兩種引用類型。所以,如果變量起初是is_ref(即完全引用-譯注),然后以拷貝的方式賦給新的變量,那么必將執(zhí)行一個完全拷貝。考慮下面的用戶空間代碼:

 zend_array_1(refcount=1, value=[])
$b = &$a;      //$a, $b -> zend_reference_1(refcount=2) -> zend_array_1(refcount=1, value=[])
$c = $a;      //// $a, $b, $c -> zend_array_1(refcount=3, value=[])

在這段代碼中,為$a創(chuàng)建并初始化了一個zval,將is_ref設(shè)為0,將refcount設(shè)為1。當(dāng)$a被$b引用時(shí),is_ref變?yōu)?,refcount遞增至2。當(dāng)拷貝至$c時(shí),Zend引擎不能只是遞增refcount至3,因?yàn)槿绱藙t$c變成了$a的完全引用。關(guān)閉is_ref也不行,因?yàn)槿绱藭?b看起來像是$a的一份拷貝而不是引用。所以此時(shí)分配了一個新的zval,并使用zval_copy_ctor()把原始(zval)的值拷貝給它。原始zval仍為is_ref==1、refcount==2,同時(shí)新zval則為is_ref=0、refcount=1?,F(xiàn)在來看另一塊內(nèi)容相同的代碼塊,只是順序稍有不同:

 zend_array_1(refcount=1, value=[])
$c = $a;  // $a, $c     -> zval_1(type=IS_ARRAY, refcount=2, is_ref=0) -> HashTable_1(value=[])
$b = &$a; // $c -> zval_1(type=IS_ARRAY, refcount=2, is_ref=0) -> HashTable_1(value=[])
          // $b, $a -> zval_1(type=IS_ARRAY, refcount=2, is_ref=1) -> HashTable_2(value=[])
          // $b 是 $a 的引用, 但卻不是 $a 的 $c, 所以這里 zval 還是需要進(jìn)行復(fù)制
          // 這樣我們就有了兩個 zval, 一個 is_ref 的值是 0, 一個 is_ref 的值是 1.

所有的變量都可以共享同一個數(shù)組,最終結(jié)果不變,$b是$a的完全引用,并且$c是$a的一份拷貝。然而這次的內(nèi)部效果稍有區(qū)別。如前,開始時(shí)為$a創(chuàng)建一個is_ref==0并且refcount=1的新zval。$c = $a;語句將同一個zval賦給$c變量,同時(shí)將refcount增至2,is_ref仍是0。當(dāng)Zend引擎遇到$b = &$a;,它想要只是將is_ref設(shè)為1,但是當(dāng)然不行,因?yàn)槟菍⒂绊懙?c。所以改為創(chuàng)建新的zval并用zval_copy_ctor()將原始(zval)的內(nèi)容拷貝給它。然后遞減原始zval的refcount以表明$a不再使用該zval。代替地,(Zend)設(shè)置新zval的is_ref為1、refcount為2,并且更新$a和$b變量指向它(新zval)。

 zend_array_1(refcount=1, value=[])
 
$b = $a;   // $a = zval_1(type=IS_ARRAY) -> zend_array_1(refcount=2, value=[])
           // $b = zval_2(type=IS_ARRAY) ---^
 
// zval 分離在這里進(jìn)行
$a[] = 1   // $a = zval_1(type=IS_ARRAY) -> zend_array_2(refcount=1, value=[1])
           // $b = zval_2(type=IS_ARRAY) -> zend_array_1(refcount=1, value=[])
 
unset($a); // $a = zval_1(type=IS_UNDEF),   zend_array_2 被銷毀
           // $b = zval_2(type=IS_ARRAY) -> zend_array_1(refcount=1, value=[])

這個過程其實(shí)挺簡單的?,F(xiàn)在整數(shù)不再是共享的,變量直接就會分離成兩個多帶帶的 zval,由于現(xiàn)在 zval 是內(nèi)嵌的所以也不需要多帶帶分配內(nèi)存,所以這里的注釋中使用 = 來表示的而不是指針符號 ->,unset 時(shí)變量會被標(biāo)記為 IS_UNDEF。

總結(jié)

PHP7 中最重要的改變就是 zval 不再多帶帶從堆上分配內(nèi)存并且不自己存儲引用計(jì)數(shù)。需要使用 zval 指針的復(fù)雜類型(比如字符串、數(shù)組和對象)會自己存儲引用計(jì)數(shù)。這樣就可以有更少的內(nèi)存分配操作、更少的間接指針使用以及更少的內(nèi)存分配。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/22093.html

相關(guān)文章

  • php7內(nèi)核閱讀(1)--數(shù)據(jù)容器zval和zend_value

    摘要:本文主要是針對,的話可以移步到慶哥的博客看,還有就是小菜我讀的是內(nèi)核剖析這本書。接下來我會使用到來調(diào)試源碼本文有參照博客中的部分內(nèi)容以及代碼。 前言 工作+實(shí)習(xí)快一年了,搞php后端開發(fā),一直很迷茫怎么提高自己,就先從php源碼開始吧,本人比較菜,本文章寫的比較趕時(shí)間,所以有什么錯誤或者漏掉的地方,望各位大神指正,多交流才能成長嘛,嘿嘿。本文主要是針對php7,php5的話可以移步到慶...

    canger 評論0 收藏0
  • 【天贏金創(chuàng)】PHP7Swoole

    摘要:但在密集計(jì)算方面比等靜態(tài)編譯語言差幾十倍甚至上百倍。一使用棧內(nèi)存在引擎和擴(kuò)展中,經(jīng)常要創(chuàng)建一個的變量,底層就是一個指針。代碼中創(chuàng)建的變量也進(jìn)行了優(yōu)化,直接在棧內(nèi)存上預(yù)分配。應(yīng)用層與底層在錯誤拋出的方式全部統(tǒng)一為異常。 原文:http://rango.swoole.com/archives/440最近PHP官方終于發(fā)布了傳說中的PHP7,雖然只是alpha版。PHP7號稱是新一代的PHP...

    MingjunYang 評論0 收藏0
  • foreach遍歷過程中的奇怪現(xiàn)象(PHP5)

    摘要:中基礎(chǔ)中的三大坑,遍歷,引用機(jī)制,數(shù)組。今天我們在講講中的一些奇怪現(xiàn)象。本文適合有一定基礎(chǔ)的。運(yùn)行流程共用一個結(jié)構(gòu)體開始遍歷數(shù)組,進(jìn)行判斷,拷貝數(shù)組是一個新的結(jié)構(gòu)體,操作的是新的結(jié)構(gòu)體。那么遍歷數(shù)組時(shí),全程與原數(shù)組無關(guān)。 PHP中基礎(chǔ)中的三大坑,foreach遍歷,引用機(jī)制&,數(shù)組。 今天我們在講講foreach中的一些奇怪現(xiàn)象。 在講解之前,可以先看看我其他相關(guān)的文章,屬于同一個大的...

    kgbook 評論0 收藏0
  • (PHP7內(nèi)核剖析-11) 模塊擴(kuò)展

    摘要:編譯工具這個腳本主要生成了編譯需要的配置以及擴(kuò)展的基本結(jié)構(gòu)這個腳本主要是獲取的安裝信息用于生成文件編寫擴(kuò)展的基本步驟通過目錄下腳本生成擴(kuò)展的基本框架修改配置設(shè)置編譯配置參數(shù)設(shè)置擴(kuò)展的源文件依賴庫函數(shù)檢查等等定義一個這樣的編譯參數(shù) 1. 編譯工具 (a).ext_skel:這個腳本主要生成了編譯需要的配置以及擴(kuò)展的基本結(jié)構(gòu) (b).php-config:這個腳本主要是獲取PHP的安裝信息...

    gplane 評論0 收藏0
  • PHP7擴(kuò)展開發(fā)(五):回調(diào)php函數(shù)開發(fā)一個并行擴(kuò)展

    摘要:起步很多時(shí)候,需要把控制權(quán)限交給用戶,或者在擴(kuò)展里完成某件事后去回調(diào)用戶的方法。在擴(kuò)展里是通過函數(shù)來調(diào)用用戶空間的函數(shù)的。收集回調(diào)函數(shù)的返回值?;卣{(diào)函數(shù)需要傳遞參數(shù)的個數(shù)。利用語言多線程庫來實(shí)現(xiàn)一個簡單的并行擴(kuò)展。 起步 很多時(shí)候,需要把控制權(quán)限交給用戶,或者在擴(kuò)展里完成某件事后去回調(diào)用戶的方法。 在PHP擴(kuò)展里是通過 call_user_function_ex 函數(shù)來調(diào)用用戶空間的函...

    _ang 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<