php中的gc

Author Avatar
Erien 3月 22, 2019

##php中的垃圾回收

###前言:引用计数
PHP中每一个变量的定义都会定义在在一个容器中,容器中提供两个额外的属性,is_refrefcount。分别代表该变量是否为引用变量,以及该变量被引用的次数;易知,refcount为1的时候is_ref为false,此时全局没有对该对象的引用,只有本身定义。



复合类型(Compound Types)ArrayObject的定义中,以键值对的形式包含多个基本类型定义的容器

以下例子来自手册:

<?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
)

###issetunset函数
isset()函数用于检测某个变量是否被定义(是否存在变量的地址),isset()函数会通过检测容器的refcount参数去检测函数的定义。


unset()用于释放一个变量,类似c语言中的free(),但是也不同,当函数对某个变量调用的时候,不会直接释放该内存,而是将该变量容器中的refcount属性减一。

###垃圾回收与变量生命周期
在旧版的php中(<=5.3),不存在主动探测的可能为垃圾变量的动作,只有当变量中的refcount减少的时候,才会产生垃圾周期并检测变量的引用数是否为零,从而发现垃圾。


但是这种方法在每一个变量的每一次引用减少时都会被全局调用,在性能上有极大的浪费,所以在新版本(php>=5.4)中,引入新的检测算法来执行垃圾回收。


在新的算法中,引入了变量数的阈值,这个值在编译好的php中是10000,为变量缓冲区的大小。当到达这个阈值的时候,将开始执行以下程序:

  • 首先,所有可能根变量都放在一个根缓冲区,并标记为可疑垃圾;
  • 然后,模拟删除每一个可疑变量(将引用次数减一)并确保每个变量会且只会被执行一次该操作;
  • 其次,模拟恢复每一个引用计数大于零的变量(该操作也会对同一变量执行一次);
  • 最后,真正删除没能恢复的变量,这些变量就为垃圾。

PHP手册-垃圾回收机制