PHP垃圾回收机制分析

发布时间:2019-11-06编辑:脚本学堂
本文详细介绍了 php中的垃圾回收机制,PHP是没有内存驻留机制的,当脚本执行完成之后所有的资源全部释放。有需要的朋友参考下。

本节内容:
php垃圾回收机制

我们知道,PHP语言是没有内存驻留机制的,当脚本执行完成之后所有的资源全部释放。

因此,在php编程中,所有的PHP的变量都存储在一个叫做zval的容器里,zval里不光存着变量的类型与值,还存储了另外两个信息,一个是is_ref,用来标识该变量是否是一个引用,另外一个是refcount,用来存储有几个变量指向两个该zval。

介绍一个函数:xdebug_debug_zval 这个函数是xdebug扩展提供的,安装xdebug扩展之后就可以在代码里调用了,安装方法和下载地址:http://xdebug.org/
这个函数就可以看到php变量的内部结构。

例子:
 

复制代码 代码示例:
<?php
$a = "new string";
xdebug_debug_zval( 'a' );
?>

输出:
a: (refcount=1, is_ref=0)='new string'

refcount=1代表有一个变量指向该zval,就是$a。
 

复制代码 代码示例:
<?php
$a = "new string";
$b = $a;
xdebug_debug_zval( 'a' );
?>

输出:
a: (refcount=2, is_ref=0)='new string'

问题分析:当变量互相赋值时,php引擎并没有创建一个新的zval,只是把这些变量都指向了相同的zval。
 

复制代码 代码示例:
<?php
$a = "new string";
$c = $b = $a;
xdebug_debug_zval( 'a' );
unset( $b, $c );
xdebug_debug_zval( 'a' );
?>

输出:
a: (refcount=3, is_ref=0)='new string'
a: (refcount=1, is_ref=0)='new string'

当调用unset,=null,或者赋给别的非空值,则refcount就会自减。
如果再调用unset($a),则该zval的refcount就减为0了,这个空间也就会被释放。

以上都是所谓的scalar types,标量类型的变量。

补充一些基础知识:

PHP中的数据类型:
PHP支持8种基本的数据类型,包括:
四种标量类型(scalar types):
boolean
integer
float (同double )
string

两种复合类型(compound types);
array
object

两种特殊类型:
resource(比如mysql的链接,mysql结果集等都属这类)
NULL

接下来,说下php中垃圾回收的问题,以上说的都是所谓的变量类型的变量,这里说下array和object。
当使用array和object时,如果处理不当,上述的垃圾回收机制就会造成一定的问题,当出现下述情况:
 

复制代码 代码示例:
<?php
$a = array( 'one' );
$a[] =& $a;
xdebug_debug_zval( 'a' );
?>

输出:
a: (refcount=2, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=...
)

此时a指向的zval的refcount是2,如果调用unset($a),这时该zval的refcount变成了1,而不是0,该zval不应该被释放,但是指向这个zval的外部链接已经没有了,即没有办法再访问到这个zval了,也就无法再减少refcount了,于是乎这个zval就挂在那了。只有当脚本执行完成之后,才会释放。

可能对于一般的应用,这种情况不会造成太大的问题,但是如果要写一个长时间运行的程序比如一个daemon程序的话,就得注意了。

不过PHP5.3更新了垃圾回收的算法,用以解决这个问题,把所有这种无头的zval都放到一个缓存区里,缓存慢了之后,就会挨个递归检查这些zval,有外连的保留,无外连得释放,算法的具体情况有时间再写。

有关php垃圾回收机制的问题,就介绍这些吧,希望有助于你的理解。
脚本学堂,祝大家学习进步。