亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > PHP > 正文

PHP內核的存儲機制(分離-改變)

2020-03-22 18:14:07
字體:
來源:轉載
供稿:網友
  • 前言: 大部分程序員看博客可能不是太喜歡看漢字比較多的文章哈,但本文確實介紹以漢字為主描述,耐心看完,對大部分人來說肯定會有收獲!
    或許你知道,或許你不知道,PHP是一個弱類型,動態的腳本語言。所謂弱類型,就是說PHP并不嚴格驗證變量類型(嚴格來講,PHP是一個中強類型語言),在申明一個變量的時候,并不需要顯示指明它保存的數據的類型。比如:$a = 1; (整形) $a ="1";(字符串)

    一直使用PHP,但它究竟什么,底層是怎么實現才成就了PHP這樣方便快捷的弱類型語言。

    最近也查閱了很多書籍,還有相關博客資料,了解到了許多關于PHP內核的一些機制。

    php簡單的理解就是一個c語言的類庫,你去php.net 下面下載一下它的源代碼就會發現,首先php的內核是zend engine ,它是一個用c語言寫的函數庫,用于處理底層的函數管理,內存管理,類管理,和變量管理。在內核上面,他們寫了很多擴展,這些擴展大多數都是獨立的。用操作系統來比喻的話,zend engine 就是一個操作系統,然后官方提供了很多“html' target='_blank'>應用程序”,只是這個“應用程序” 不是media play 而是 mysql , libxml,dom。當然,你也可以根據zend engine 的api 開發自己的擴展。



    下邊開始介紹下PHP變量在內核中的存儲機制。

    PHP是若類型語言,也就是說一個PHP變量可以保存任何的數據類型。但PHP是使用C語言編寫的,而C語言是強類型語言是吧,每個變量都會有固定的類型,(一顆通過強類型轉變,不過有可能出現問題),那在Zend引擎中如何做到一個變量保存任何數據類型?下邊請看它存儲結構體。 打開Zend/zend.h頭文件,會發現下列結構體Zval:

    1.zval結構

     typedef struct _zval_struct zval;
     typedef union _zvalue_value {    long lval;      /* long value */    double dval;    /* double value */    struct {    char *val; //4字節    int len;   //4字節    } str;    HashTable *ht;    /* hash table value */    zend_object_value obj; } zvalue_value;

     struct _zval_struct {    /* Variable information */    zvalue_value value;  /* 變量值保存在這里 12字節*/    zend_uint refcount;//4字節,變量引用計數器    zend_uchar type;   /* active type變量類型 1字節*/    zend_uchar is_ref;//是否變量被&引用,0表示非引用,1表示引用,1字節    };


    2.zend_uchar type
    PHP中的變量包括四種標量類型(bool,int,float,string),兩種復合類型(array, object)和兩種特殊的類型(resource 和NULL)。在zend內部,這些類型對應于下面的宏(代碼位置 phpsrc/Zend/zend.h) Zend根據type值來決定訪問value的哪個成員,可用值如下:


    3.zend_uint refcount__gc


    該值實際上是一個計數器,用來保存有多少變量(或者符號,symbols,所有的符號都存在符號表(symble table)中, 不同的作用域使用不同的符號表,關于這一點,我們之后會論述)指向該zval。在變量生成時,其refcount=1,典型的賦值操作如$a = $b會令zval的refcount加1,而unset操作會相應的減1。在PHP5.3之前,使用引用計數的機制來實現GC,如果一個zval的refcount較少到0,那么Zend引擎會認為沒有任何變量指向該zval,因此會釋放該zval所占的內存空間。但,事情有時并不會那么簡單。后面我們會看到,單純的引用計數機制無法GC掉循環引用的zval(詳見后舉例3),即使指向該zval的變量已經被unset,從而導致了內存泄露(Memory Leak)。


    4.is_ref__gc
    . 這個字段用于標記變量是否是引用變量。對于普通的變量,該值為0,而對于引用型的變量,該值為1。這個變量會影響zval的共享、分離等。關于這點,我們之后會有論述。

    正如名字所示,ref_count__gc和is_ref__gc是PHP的GC機制所需的很重要的兩個字段,這兩個字段的值,可以通過xdebug等調試工具查看。

    下面我們圍繞zval,展開敘述,PHP變量到底是怎么個存儲機制。

    Xdebug的安裝我在前邊PHPstorm Xdebug調試也介紹過,這里不贅述,請看: phpstorm+Xdebug斷點調試PHP

    安裝成功后,你的腳本中,可以通過xdebug_debug_zval打印Zval的信息,用法:

     $var = 1; debug_zval_dump($var); $var_dup = $var; debug_zval_dump($var);


    實例一:

        $a = 1;    $b = $a;    $c = $b;    $d = &$c; // 在一堆非引用賦值中,插入一個引用



    整個過程圖示如下:

    ---------------------------------------------------------

    實例二:

       $a = 1;    $b = &$a;    $c = &$b;    $d = $c; // 在一堆引用賦值中,插入一個非引用


    整個過程圖示如下:




    通過實例一、二,展現了,這就是PHP的copy on write寫時分離機制、change on write寫時改變機制

    過程:

    PHP在修改一個變量以前,會首先查看這個變量的refcount,如果refcount大于1,PHP就會執行一個分離的例程,

    對于上面的實例一代碼,當執行到第四行的時候,PHP發現$c指向的zval的refcount大于1,那么PHP就會復制一個新的zval出來,將原zval的refcount減1,并修改symbol_table,使得$a,$b和$c分離(Separation)。這個機制就是所謂的copy on write(寫時復制/寫時分離)。把$d指向的新zval的is_ref的值 == 1 ,這個機制叫做change on write(寫時改變)


    結論:

    分離指的是:分離兩個變量存儲的zval的位置,讓分開不指向同一個空間! (那如何判定是否要分離呢,依據是什么?見下邊)

    改變指的是,有&引用賦值時,要把新開辟的zval 的 is_ref 賦值為1

    判定是否分離的條件:如果is_ref =1 或recount == 1,則不分離
    if((*val)->is_ref || (*val)->refcount<2){          //不執行Separation        ... ;//process  }




    ---------------------------------------------------------------------------------------------------
    實例三:(內存是如何泄漏的)數組變量與普通變量生成的zval非常類似,但也有很大不同舉例:
    $a = $array('one');  $a[] = &$a;  xdebug_debug_zval('a'); 

    debug_zval_dump打印出zval的結構是:
    a: (refcount=2, is_ref=1)=array (    0 => (refcount=1, is_ref=0)='one',     1 => (refcount=2, is_ref=1)=...)

    上述輸出中,…表示指向原始數組,因而這是一個循環的引用。如下圖所示:





    現在,我們對$a執行unset操作,這會在symbol table中刪除相應的symbol,同時,zval的refcount減1(之前為2),也就是說,現在的zval應該是這樣的結構:
    unset($a);(refcount=1, is_ref=1)=array (    0 => (refcount=1, is_ref=0)='one',     1 => (refcount=1, is_ref=1)=...)

    (應該ref_count=1)

    (unset,其實就是打斷$a在 符號表(symble table) 與zval 的一個指針映射關系。)

    這時,不幸的事情發生了!

      Unset之后,雖然沒有變量指向該zval,但是該zval卻不能被GC(指PHP5.3之前的單純引用計數機制的GC)清理掉,$a 被釋放,但是$a里的$a[1]也指向了該zval,它沒有被釋放,導致zval的refcount均大于0。這樣,這些zval實際上會一直存在內存中,直到請求結束(參考SAPI的生命周期)。在此之前,這些zval占據的內存不能被使用,便白白浪費了,換句話說,無法釋放的內存導致了內存泄露。

      如果這種內存泄露僅僅發生了一次或者少數幾次,倒也還好,但如果是成千上萬次的內存泄露,便是很大的問題了。尤其在長時間運行的腳本中(例如守護程序,一直在后臺執行不會中斷),由于無法回收內存,最終會導致系統“再無內存可用”,所以說,一定要避免這種操作。



    垃圾回收機制:
    1.php原來是通過引用計數器來實現內存回收,也就是是多個php變量可能會引用同一份內存,這種情況unset掉其中一個是不會釋放內存的;
    例如:$a = 1; $b = $a; unset($a);//$a開辟的內存不會回收
    2.離開了變量的作用域后變量所占用的內存就會被自動清理(不包含靜態變量,靜態變量在腳本加載時創建,在腳本結束時釋放), 如函數或方法內的局部變量,對這些局部變量進行unset在函數外來看內存也是沒有減少的。 3.引用計數有個缺陷,就是當循環引用出現時,計數器沒法清0,內存占用會持續到頁面訪問結束。 對于這個問題PHP5.3中增加了垃圾回收機制。具體可以查閱文檔:http://php.net/manual/zh/features.gc.php 垃圾回收機制就是最早在Lisp中被提出,關于更多垃圾回收的信息. 參見維基百科:http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)


    本文參考文獻:鳥哥的深入變量引用/分離 http://www.laruence.com/2008/09/19/520.html


    本文鏈接地址:http://blog.csdn.net/ty_hf/article/details/51057954
    啊~終于寫完了,清明三天假期也就這么過去了,今天4月4號,明天開始準備上班啦!~奮斗

    PHP編程

    鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

  • 發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
    亚洲国产成人精品一区二区| 精品露脸国产偷人在视频| 欧美久久精品午夜青青大伊人| 欧美大片免费看| 中文字幕亚洲欧美日韩高清| 国产+成+人+亚洲欧洲| 国产一区二区丝袜高跟鞋图片| 久久亚洲私人国产精品va| 国产欧美亚洲视频| 日韩av中文在线| 91久久中文字幕| 日韩av免费在线看| 日韩精品在线观看一区| 一区二区亚洲欧洲国产日韩| 欧美日韩免费在线| 91探花福利精品国产自产在线| 国产精品私拍pans大尺度在线| 久久6精品影院| 日本精品一区二区三区在线播放视频| 亚洲免费视频一区二区| 亚洲欧美国产精品va在线观看| 国产v综合v亚洲欧美久久| 日韩视频精品在线| 亚洲va欧美va国产综合剧情| 中文日韩在线视频| 精品亚洲一区二区| 久久久国产一区二区三区| 欧美一区二三区| 中文字幕日韩av综合精品| 亚洲激情视频网| 亚洲网站视频福利| 国产在线播放91| 国内精品久久久久久中文字幕| 亚洲国产成人久久| 欧美成人免费在线观看| 亚洲日本中文字幕免费在线不卡| 亚洲人成电影在线观看天堂色| 亚洲已满18点击进入在线看片| 亚洲第一区在线观看| 久久久久久亚洲精品| 久久久亚洲欧洲日产国码aⅴ| 在线视频欧美性高潮| 欧美裸体男粗大视频在线观看| 欧美成人精品一区二区| 在线观看欧美视频| 国产精品免费久久久| 欧美亚洲另类激情另类| 亚洲人成自拍网站| 国产午夜精品视频免费不卡69堂| 亚洲视频第一页| 亚洲精品一区二区久| 高清在线视频日韩欧美| 国产精品爽爽爽| 91精品91久久久久久| 国产午夜精品一区理论片飘花| 国产一区欧美二区三区| 97视频网站入口| 久久影院免费观看| 亚洲综合大片69999| 蜜月aⅴ免费一区二区三区| 91在线|亚洲| 91精品国产91久久久久久最新| 自拍亚洲一区欧美另类| xxx成人少妇69| 97精品在线视频| 午夜精品三级视频福利| 亚洲淫片在线视频| 中文字幕日韩av| 午夜精品久久久久久久久久久久| 欧美黑人性生活视频| 最近2019中文字幕mv免费看| 中文字幕久久亚洲| 国产精品成人在线| 91免费在线视频网站| 国产一级揄自揄精品视频| 高清欧美性猛交xxxx| 中文字幕日韩欧美| 欧美成人午夜免费视在线看片| 一本色道久久88综合日韩精品| 久久夜色精品国产| 91国偷自产一区二区三区的观看方式| 精品香蕉在线观看视频一| 亚洲视频在线观看| 日本中文字幕不卡免费| 国产午夜精品全部视频播放| 日本视频久久久| 日本一本a高清免费不卡| 成人午夜一级二级三级| 久久久在线观看| 欧美激情精品久久久| 亚洲精品wwwww| 性金发美女69hd大尺寸| 国产精品日韩精品| 亚洲一区精品电影| 国产精品久久久久久久久| 成人免费观看49www在线观看| 亚洲精品欧美极品| 国产精品劲爆视频| 久久亚洲一区二区三区四区五区高| 羞羞色国产精品| 国外成人免费在线播放| 亚洲国产成人精品女人久久久| 日本亚洲精品在线观看| 日韩美女免费线视频| 91精品国产777在线观看| 蜜月aⅴ免费一区二区三区| 欧美刺激性大交免费视频| 91精品在线播放| 中文综合在线观看| 成人黄色在线观看| 欧美在线播放视频| 国产精品偷伦免费视频观看的| 国精产品一区一区三区有限在线| 亚洲sss综合天堂久久| 欧美日韩国产一区二区三区| 日韩av不卡在线| 欧美高清性猛交| 奇米影视亚洲狠狠色| 国产精品久在线观看| 亚洲欧洲在线观看| 亚洲跨种族黑人xxx| 奇门遁甲1982国语版免费观看高清| 日韩毛片在线看| 91九色视频导航| 国产精品羞羞答答| 国产成人精品优优av| 久久在线免费视频| 日韩在线观看免费av| 欧美亚洲午夜视频在线观看| 久久成人亚洲精品| 精品国内亚洲在观看18黄| 亚洲成人激情视频| 26uuu另类亚洲欧美日本一| 国产成人精品日本亚洲专区61| 国产在线拍揄自揄视频不卡99| 久久精品视频中文字幕| 国产精品久久久久久网站| 亚洲国产婷婷香蕉久久久久久| 欧美色欧美亚洲高清在线视频| 亚洲日韩中文字幕| 精品国内产的精品视频在线观看| 亚洲欧美一区二区三区四区| 欧美又大粗又爽又黄大片视频| 国产成人综合亚洲| 国产精品久久91| 91啪国产在线| 日韩av一区二区在线观看| 亚洲精品视频在线播放| 97激碰免费视频| 8090成年在线看片午夜| 国产欧美欧洲在线观看| 国产精品一区二区久久国产| 亚洲性生活视频在线观看| 亚洲欧美日韩国产中文专区| 亚洲天堂成人在线视频| 亚洲级视频在线观看免费1级| 欧美疯狂xxxx大交乱88av| 亚洲精品视频在线播放| 精品一区电影国产| 欧美激情中文字幕乱码免费| 啊v视频在线一区二区三区| 精品亚洲永久免费精品| 日韩有码片在线观看| 日本一区二区在线播放|