php中的gc
##php中的垃圾回收
###前言:引用计数
PHP中每一个变量的定义都会定义在在一个容器中,容器中提供两个额外的属性,is_ref
和 refcount
。分别代表该变量是否为引用变量,以及该变量被引用的次数;易知,refcount
为1的时候is_ref
为false,此时全局没有对该对象的引用,只有本身定义。
在复合类型(Compound Types) 如Array
、Object
的定义中,以键值对的形式包含多个基本类型定义的容器
以下例子来自手册:
<?php
$a = array( 'meaning' => 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );
?>
//内部定义形式
a: (refcount=1, is_ref=0)=array (
'meaning' => (refcount=1, is_ref=0)='life',
'number' => (refcount=1, is_ref=0)=42
)
###isset
和unset
函数isset()
函数用于检测某个变量是否被定义(是否存在变量的地址),isset()
函数会通过检测容器的refcount
参数去检测函数的定义。unset()
用于释放一个变量,类似c语言中的free()
,但是也不同,当函数对某个变量调用的时候,不会直接释放该内存,而是将该变量容器中的refcount
属性减一。
###垃圾回收与变量生命周期
在旧版的php中(<=5.3),不存在主动探测的可能为垃圾变量的动作,只有当变量中的refcount
减少的时候,才会产生垃圾周期并检测变量的引用数是否为零,从而发现垃圾。
但是这种方法在每一个变量的每一次引用减少时都会被全局调用,在性能上有极大的浪费,所以在新版本(php>=5.4)中,引入新的检测算法来执行垃圾回收。
在新的算法中,引入了变量数的阈值,这个值在编译好的php中是10000,为变量缓冲区的大小。当到达这个阈值的时候,将开始执行以下程序:
- 首先,所有可能根变量都放在一个根缓冲区,并标记为可疑垃圾;
- 然后,模拟删除每一个可疑变量(将引用次数减一)并确保每个变量会且只会被执行一次该操作;
- 其次,模拟恢复每一个引用计数大于零的变量(该操作也会对同一变量执行一次);
- 最后,真正删除没能恢复的变量,这些变量就为垃圾。