php內核閱讀(2)--淺談 gc回收機制

自嘲)。。。。。2333,我以爲這是由於在php語言層面就幫咱們解決了內存回收的問題,但這讓我在和java大牛們吹牛逼的時候,聽到什麼內存泄露。。。。(納尼,我tmd怎麼歷來沒碰見過)一臉懵逼。php

本人小菜,若是下面所寫有什麼錯誤的地方,請大神指出,而且下文,不少都是讀書+看源碼以後本身的總結。java

前言

在上一篇中我淺談的PHP中的基本數據容器,zend_value,zval算法

實際存儲數據的並不全是zend_value,還有一個被zend_value經過指針指向的具體的數據存儲結構體,如_zend_array,_zend_stringui

struct _zend_string {
    zend_refcounted_h gc;
    zend_ulong        h;                /* hash value */
    size_t            len;
    char              val[1];
};
struct _zend_array {
    zend_refcounted_h gc;
    union {
        struct {
            ZEND_ENDIAN_LOHI_4(
                zend_uchar    flags,
                zend_uchar    nApplyCount,
                zend_uchar    nIteratorsCount,
                zend_uchar    consistency)
        } v;
        uint32_t flags;
    } u;
    uint32_t          nTableMask;
    Bucket           *arData;
    uint32_t          nNumUsed;
    uint32_t          nNumOfElements;
    uint32_t          nTableSize;
    uint32_t          nInternalPointer;
    zend_long         nNextFreeElement;
    dtor_func_t       pDestructor;
};

注意每一個結構體中都有一個名爲gc的變量,這個變量其實就是 zend_refcounted_h 引用計數debug

內存回收的兩種狀況

  • 正常的變量在生命週期完成以後的回收。指針

    這種狀況也就是說當zend_value中refCount==0的時候,這時候屬於正常的內存回收。
  • 垃圾回收
    所謂垃圾: 就是指經過循環引用(本身引用本身,目前只在array,object類型中有出現)的形式而致使refcount永遠不爲0。這種狀況下,若是不處理,可是這些內存沒法釋放,到時內存泄露code

    代碼以下:生命週期

    $a  = array(1,2 );
     xdebug_debug_zval("a");
    
    $a[] = &$a;
    xdebug_debug_zval("a");
    
    $b=$a;
    
    unset($a);
    xdebug_debug_zval("a");
    xdebug_debug_zval("b");

    結果以下圖片

    a:
    (refcount=1, is_ref=0)
    array (size=2)
      0 => (refcount=0, is_ref=0)int 1
      1 => (refcount=0, is_ref=0)int 2
    a:
    (refcount=2, is_ref=1)
    array (size=3)
      0 => (refcount=0, is_ref=0)int 1
      1 => (refcount=0, is_ref=0)int 2
      2 => (refcount=2, is_ref=1)
        &array<
    a:
    (refcount=0, is_ref=0)*uninitialized*
    b:
    (refcount=2, is_ref=0)
    array (size=3)
      0 => (refcount=0, is_ref=0)int 1
      1 => (refcount=0, is_ref=0)int 2
      2 => (refcount=1, is_ref=1)
        &array<

    按照正常邏輯,當unset($a),以後,其對應的zeng_value的refCount=1,is_ref=0,可是實際上它倒是等於refCount=2,is_ref=0, 這就致使,就算是unset($b),以後,refCount=1,is_ref=0,這種結果,像上面當refCount=0後正常回收內存。內存

    ![圖片上傳中...]

    這就是 垃圾。

    當出現垃圾以後,php的zend引擎有對應的垃圾回收機制。

    其實這種機制的原理就是 :

    (1).將這些垃圾放入buffer中。
       
       (2).當buffer到達必定數量以後,啓動對全部垃圾的value自身的refCount-1,並將zend_refcounted中的gc_info變量置爲GC_GRAY
    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;
    (3).遍歷當前buffer,當refCount=0是則表示當前的這個value的確是個垃圾,則將zend_refcounted中的gc_info變量置爲GC_WHITE。而後由於全部的value中都減1,因此再次遍歷,將那些減一後refcount !=0 的value+1,而後將zend_refcounted中的gc_info變量置爲GC_BLACK
       
       (4).最後遍歷buffer,將buffer中的value的zend_refcounted中的gc_info爲GC_WHITE刪除
    
    
       講完GC垃圾回收算法的原理,貌似我尚未講在何時會觸發將這個**可能**的垃圾放入buffer。。。。。。
       
       ***觸發這個機制的時機是每次出現refCount減小時候。***
相關文章
相關標籤/搜索