background image

Reference Counting 简单直观,实现方便,但却存在一个致命的缺陷,就是容易造
成内存泄露。很多朋友可能已经意识到了,如果存在循环引用,那么

Reference 

Counting 就可能导致内存泄露。例如下面的代码:

?

1
2
3
4
5

<?php 
$a

 

= array(); 

$a[] = & $a; 
unset($a); 
?>

这段代码首先建立了数组

a,然后让 a 的第一个元素按引用指向 a,这时 a 的 zval 的

refcount 就变为 2,然后我们销毁变量 a,此时 a 最初指向的 zval 的 refcount 为
1,但是我们再也没有办法对其进行操作,因为其形成了一个循环自引用,如下图所示:

其中灰色部分表示已经不复存在。由于

a 之前指向的 zval 的 refcount 为 1(被其

HashTable 的第一个元素引用),这个 zval 就不会被 GC 销毁,这部分内存就泄露了。

这里特别要指出的是,

PHP 是通过符号表(Symbol Table)存储变量符号的,全局

有一个符号表,而每个复杂类型如数组或对象有自己的符号表,因此上面代码中,

a

a[0]是两个符号,但是 a 储存在全局符号表中,而 a[0]储存在数组本身的符号表中,

且这里

a 和 a[0]引用同一个 zval(当然符号 a 后来被销毁了)。希望读者朋友注意分

清符号(

Symbol)的 zval 的关系。

PHP 只用于做动态页面脚本时,这种泄露也许不是很要紧,因为动态页面脚本的生

命周期很短,

PHP 会保证当脚本执行完毕后,释放其所有资源。但是 PHP 发展到目前

已经不仅仅用作动态页面脚本这么简单,如果将

PHP 用在生命周期较长的场景中,例

如自动化测试脚本或

deamon 进程,那么经过多次循环后积累下来的内存泄露可能就