PHP知识梳理_GC

参考PHP版本7.1

1.PHP 变量结构

php变量在zend中的定义分为zval zend_value, 
    zval存储变量名 和指向value的指针,
    zend_value存储具体的变量值
//zend_types.h
typedef struct _zval_struct     zval;

typedef union _zend_value {
    zend_long         lval;    //int整形
    double            dval;    //浮点型
    zend_refcounted  *counted;
    zend_string      *str;     //string字符串
    zend_array       *arr;     //array数组
    zend_object      *obj;     //object对象
    zend_resource    *res;     //resource资源类型
    zend_reference   *ref;     //引用类型,通过&$var_name定义的
    zend_ast_ref     *ast;     //下面几个都是内核使用的value
    zval             *zv;
    void             *ptr;
    zend_class_entry *ce;
    zend_function    *func;
    struct {
        uint32_t w1;
        uint32_t w2;
    } ww;
} zend_value;

struct _zval_struct {
    zend_value        value; //变量实际的value
    union {
        struct {
            ZEND_ENDIAN_LOHI_4( //这个是为了兼容大小字节序,小字节序就是下面的顺序,大字节序则下面4个顺序翻转
                zend_uchar    type,         //变量类型
                zend_uchar    type_flags,  //类型掩码,不同的类型会有不同的几种属性,内存管理会用到
                zend_uchar    const_flags,
                zend_uchar    reserved)     //call info,zend执行流程会用到
        } v;
        uint32_t type_info; //上面4个值的组合值,可以直接根据type_info取到4个对应位置的值
    } u1;
    union {
        uint32_t     var_flags;
        uint32_t     next;                 //哈希表中解决哈希冲突时用到
        uint32_t     cache_slot;           /* literal cache slot */
        uint32_t     lineno;               /* line number (for ast nodes) */
        uint32_t     num_args;             /* arguments number for EX(This) */
        uint32_t     fe_pos;               /* foreach position */
        uint32_t     fe_iter_idx;          /* foreach iterator index */
    } u2; //一些辅助值
};
    zend_value 中定义了 zend_refcount 即当前数据的引用次数,引用的变量每销毁一个 zend_refcount -1,正常情况下。函数执行完毕后会减为0,内存自动销毁回收zend_value.
    $a = array[];
    $a[] = &$a;
    unset($a);
    如上当出现类似自身引用自身时,unset后 zend_refcount 为1,这时候zend_value就有内存垃圾,zend的GC 机制就会将该 zend_value 放入GC的处理队列中。等待GC处理

2. Zend GC

 zendGC 管理了一个buffer 作为作为垃圾缓存区的存储地址, buffer使用双向链表实现 长度10000,当有垃圾产生时 加入到链表中,当链表满时触发GC进行清理。
GC清理过程: 
    1.使用深度优先算法,对垃圾成员进行遍历,将垃圾成员的refcount 减1。并标记状态为 grey(灰)。 
        为什么使用深度优先?为了检测成员的子成员引用
    2.重新遍历buffer,将refcount的值为0的 状态改为 WHITE(白),此类即为真正的垃圾数据,需要清理。如果非0 则表明除自身引用外,还有其他外部引用.非垃圾数据将refcount +1.将状态标记为黑色。
    3.遍历buffer, 将非WHITE状态的数据全部还原,剩余WHITE状态的均为垃圾数据 清空链表。

你可能感兴趣的:(PHP知识梳理_GC)