欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

PHP 是如何做垃圾回收的

程序员文章站 2022-12-23 17:13:26
PHP 是如何做垃圾回收的 包含 php 5 与 php7 的变量实现和垃圾回收的对比 变量的实现 PHP 的变量是弱类型的,可以表示整数、浮点数、字符串等类型。PHP 的变量是使用结构体 zval 表示的 PHP 5. zval 和 zend_value 结构 PHP 7.0 zval 和 zen ......

php 是如何做垃圾回收的

包含 php 5 与 php7 的变量实现和垃圾回收的对比

变量的实现

php 的变量是弱类型的,可以表示整数、浮点数、字符串等类型。php 的变量是使用结构体 zval 表示的

php 5.* zval 和 zend_value 结构

struct _zval_struct { // 结构体
    zvalue_value value;
    zend_uint refcount__gc;
    zend_uchar type;
    zend_uchar is_ref__gc;
}

typedef union _zvalue_value { // 联合体
    long lval;
    double dval;
    struct {
        char *val;
        int len;
    } str; // 字符串
    hashtable *ht; // 数组
    zend_object_value obj; // 对象
    zend_ast *ast;
} zvalue_value;

php 7.0 zval 和 zend_value 结构

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;
};

php5 与 php7 引用计数的对比

php 5.* 变量赋值等操作引用计数如图所示,在倒数第二步,会形成一个循环引用,并且在 unset 操作之后,会产生垃圾。

PHP 是如何做垃圾回收的

php 7 的计数放到了具体的 value 中,zval 不存在写时复制(写时分离)。

并且 php 7 的有一个专门的 zend_reference 用来表示引用。

PHP 是如何做垃圾回收的

有了以上关于 php 变量存储的知识,我们可以理解一下 php 是如何做垃圾回收的了。

什么是垃圾

首先,我们需要定义什么是垃圾。

  1. refcount 增加的不是
  2. refcount 等于0的不是,这个会被直接清除
  3. refcount 减少,并且不等于0的才是垃圾

垃圾收集

  1. php7 要求数据类型是数组和对象,并且 type_flag 是 is_type_collectable
  2. 没有在缓冲区中存在过
  3. 没有被标记过
  4. 标记为紫色,并且放到缓冲区中

回收算法

论文:https://researcher.watson.ibm.com/researcher/files/us-bacon/bacon01concurrent.pdf

php 5.3 版本以及之后的版本

  1. 将垃圾放到一个 root 池中
  2. 当满 10000 个节点的时候进行垃圾回收
  3. 遍历双向链表中的节点 refcount-1
  4. 遍历双向链表将 refcount=0 的节点删除,到free队列中
  5. 对 refcount!=0 的 refcount+1

PHP 是如何做垃圾回收的