PHP7时代下的ZVAL以及垃圾回收gc的改变

首先,我们需要搞清楚什么是ZVAL,我们PHP底层是C语言写的,所以我们PHP里面的ZVAL是C语言里面的一个结构体,用来保存我们PHP语言创建的变量。既然是一个结构体,那么里面就会有很多的变量来保存我们不同的变量类型。PHP5时代结构体里面的字段比较少,虽然足够用了,但是当在某些情况下,会造成很大的资源浪费。由于字段的不足。所以在PHP7时代,增加了很多字段来改进这些不足

PHP5的ZVAL:

struct _zval_struct {
     union {
          long lval;
          double dval;
          struct {
               char *val;
               int len;
          } str;
          HashTable *ht;
          zend_object_value obj;
          zend_ast *ast;
     } value;
     zend_uint refcount__gc;
     zend_uchar type;
     zend_uchar is_ref__gc;
};

PHP7的ZVAL

struct _zval_struct {
     union {
          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;
     } value;
    union {
        struct {
            ZEND_ENDIAN_LOHI_4(
                zend_uchar    type,         /* active type */
                zend_uchar    type_flags,
                zend_uchar    const_flags,
                zend_uchar    reserved)     /* call info for EX(This) */
        } v;
        uint32_t type_info;
    } u1;
    union {
        uint32_t     var_flags;
        uint32_t     next;                 /* hash collision chain */
        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;
};

我们可以看到,增加了很多的字段。这些字段的添加对于性能提升和节约资源有很大的帮助。

引用(REFERENCE)在PHP5的时候是一个标志位, 而在PHP7以后我们把它变成了一种新的类型:IS_REFERNCE. 然而引用是一种很常见的应用, 所以这个变化带来了很多的变化, 也给我们在做PHP7开发的时候, 因为有的时候疏忽忘了处理这个类型, 而带来不少的bug.

  • 垃圾回收机制改变
    1、PHP5标量数据类型会计数,PHP7标量数据类型不再计数,不需要单独分配内存
    2、PHP7的zval 需要的内存不再是单独从堆上分配,不再自己存储引用计数。
    3、PHP7的复杂数据类型(比如数组和对象)的引用计数由其自身来存储。

  • 垃圾回收算法

1、对每个根缓冲区中的根zval按照深度优先遍历算法遍历所有能遍历到的zval,并将每个zval的refcount减1,同时为了避免对同一zval多次减1(因为可能不同的根能遍历到同一个zval),
  每次对某个zval减1后就对其标记为“已减”。

2、再次对每个缓冲区中的根zval深度优先遍历,如果某个zval的refcount不为0,则对其加1,否则保持其为0。

3、清空根缓冲区中的所有根(注意是把这些zval从缓冲区中清除而不是销毁它们),然后销毁所有refcount为0的zval,并收回其内存。

如果不能完全理解也没有关系,只需记住PHP5.3的垃圾回收算法有以下几点特性:

1、并不是每次refcount减少时都进入回收周期,只有根缓冲区满额后在开始垃圾回收。

2、可以解决循环引用问题。

3、可以总将内存泄露保持在一个阈值以下。

上一篇:php7——Linux/Mac源码安装php7


下一篇:php7 Error处理