往上面讲述PHP垃圾回收机制的文章很多,官网的介绍,还有下面一些
http://php-internal.com/book/?p=chapt06/06-04-01-new-garbage-collection
http://blog.youkuaiyun.com/phpkernel/article/details/5734743等等。
新的垃圾回收机制,是为了防止引用计数中变量的循环引用引起的内存泄露,如果没有主动unset变量,首先变量的赋值操作会进行其引用数-1是否为0的判断,如果不为0,加入垃圾回收的机制的代码。如果主动unset 的话,跟踪代码,会调用_zval_ptr_dtor函数,进而调用GC_ZVAL_CHECK_POSSIBLE_ROOT执行垃圾回收机制。
代码才是硬道理:
static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value, int is_tmp_var TSRMLS_DC)
{
zval *variable_ptr = *variable_ptr_ptr;
zval garbage;
if (variable_ptr == EG(error_zval_ptr)) {
if (is_tmp_var) {
zval_dtor(value);
}
return EG(uninitialized_zval_ptr);
}
if (Z_TYPE_P(variable_ptr) == IS_OBJECT && Z_OBJ_HANDLER_P(variable_ptr, set)) {
Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
return variable_ptr;
}
//变量赋值的各种情况
if (PZVAL_IS_REF(variable_ptr)) {
if (variable_ptr!=value) {
zend_uint refcount = Z_REFCOUNT_P(variable_ptr);
garbage = *variable_ptr;
*variable_ptr = *value;
Z_SET_REFCOUNT_P(variable_ptr, refcount);
Z_SET_ISREF_P(variable_ptr);
if (!is_tmp_var) {
zendi_zval_copy_ctor(*variable_ptr);
}
zendi_zval_dtor(garbage);
return variable_ptr;
}
} else {
if (Z_DELREF_P(variable_ptr)==0) {//判断变量引用数-1后是否为0
if (!is_tmp_var) {
if (variable_ptr==value) {//左右值是否相等
Z_ADDREF_P(variable_ptr);
} else if (PZVAL_IS_REF(value)) {
garbage = *variable_ptr;
*variable_ptr = *value;
INIT_PZVAL(variable_ptr);
zval_copy_ctor(variable_ptr);
zendi_zval_dtor(garbage);
return variable_ptr;
} else {
Z_ADDREF_P(value);
*variable_ptr_ptr = value;
if (variable_ptr != &EG(uninitialized_zval)) {
GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr);
zval_dtor(variable_ptr);
efree(variable_ptr);
}
return value;
}
} else {
garbage = *variable_ptr;
*variable_ptr = *value;
INIT_PZVAL(variable_ptr);
zendi_zval_dtor(garbage);
return variable_ptr;
}
} else { /* we need to split */
GC_ZVAL_CHECK_POSSIBLE_ROOT(*variable_ptr_ptr); //若不为零加入垃圾回收机制 (不知道增加if (variable_ptr==value) 条件会不会更好?循环引用嘛,直接判断循环又没成立,给自己留个问题)
if (!is_tmp_var) {
if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) {
ALLOC_ZVAL(variable_ptr);
*variable_ptr_ptr = variable_ptr;
*variable_ptr = *value;
Z_SET_REFCOUNT_P(variable_ptr, 1);
zval_copy_ctor(variable_ptr);
} else {
*variable_ptr_ptr = value;
Z_ADDREF_P(value);
}
} else {
ALLOC_ZVAL(*variable_ptr_ptr);
Z_SET_REFCOUNT_P(value, 1);
**variable_ptr_ptr = *value;
}
}
Z_UNSET_ISREF_PP(variable_ptr_ptr);
}
return *variable_ptr_ptr;
}
上面是变量赋值的时候,会调用的函数。
unset 的时候,会将opcode 的类型改变,下面是unset 的代码:
在执行函数中,临时变量会调用zval_dtor(直接销毁),一般的变量会调用zval_ptr_dtor。
至于垃圾回收机制的算法,一些数据机构,其他的文章写的已经相当详细,不为自己做记录了。