PHP垃圾回收机制简析(基于7.4)

前言,以下内容基于php 7.4.3源码进行简单讲解,以加深自己对PHP的理解。由于本人也不是很厉害,如有错误欢迎通过邮箱联系我更正。

源码分析

首先找到php中的变量指针的结构体 zval 的定义

// Zend/zend_types.h
......
    typedef struct _zval_struct     zval;
......

接着找 _zval_struct的定义

// Zend/zend_types.h
......
struct _zval_struct {
    zend_value        value;            /* value */
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    type,         /* active type */
                zend_uchar    type_flags,
                union {
                    uint16_t  extra;        /* not further specified */
                } u)
        } v;
        uint32_t type_info;
    } u1;
    union {
        uint32_t     next;                 /* hash collision chain */
        uint32_t     cache_slot;           /* cache slot (for RECV_INIT) */
        uint32_t     opline_num;           /* opline number (for FAST_CALL) */
        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 */
        uint32_t     access_flags;         /* class constant access flags */
        uint32_t     property_guard;       /* single property guard */
        uint32_t     constant_flags;       /* constant flags */
        uint32_t     extra;                /* not further specified */
    } u2;
};
......

u1 看上去比较像用来识别变量类型的一个结构, u2 应该是缓存方面使用的一些辅助的信息。所以研究垃圾回收应该就集中在研究 u2 和暂时还不了解结构的 zend_value 。所以接着研究一下 zend_value 这个结构体。回到上面的那个文件,找到 _zend_value 的定义部分。

// Zend/zend_types.h
......
typedef union _zend_value {
    zend_long         lval;             /* long value */
    double            dval;             /* double value */
    zend_refcounted  *counted;
    zend_string      *str;
    zend_array       *arr;
    zend_object      *obj;
    zend_resource    *res;
    zend_reference   *ref;
    zend_ast_ref     *ast;
    zval             *zv;
    void             *ptr;
    zend_class_entry *ce;
    zend_function    *func;
    struct {
        uint32_t w1;
        uint32_t w2;
    } ww;
} zend_value;
......

注意上面代码的第11行,一个熟悉的单词 reference ,这里就会联想起之前 php5的时候也有类似的结构,所以应该就是它了

// Zend/zend_types.h
......
typedef struct _zend_reference  zend_reference;
......
struct _zend_reference {
    zend_refcounted_h              gc;
    zval                           val;
    zend_property_info_source_list sources;
};

......

typedef struct _zend_refcounted_h {
    uint32_t         refcount;          /* reference counter 32-bit */
    union {
        uint32_t type_info;
    } u;
} zend_refcounted_h;

......

和之前的结构一样,很顺利的找到了上面的结构。 zend_refcounted_h 看到这个就可以知道了,php7对代码做了调整,但是实现原理应该还是一样的,后面的步骤其实就基本与php5相似了。

结合php5了解工作原理

参考内容
[1]php.net 垃圾回收机制

实际代码验证

点赞