参考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状态的均为垃圾数据 清空链表。
网友评论