background image

浅谈 PHP 5 中垃圾回收算法的演化

 PHP 是一门托管型语言,在 PHP 编程中程序员不需要手工处理内存资源的分配与释放
(使用 C 编写 PHP 或 Zend 扩展除外),这就意味着 PHP 本身实现了垃圾回收机制(Garbage 
Collection)。现在如果去 PHP 官方网站(php.net)可以看到,目前 PHP5 的两个分支版本
PHP5.2 和 PHP5.3 是分别更新的,这是因为许多项目仍然使用 5.2 版本的 PHP,而 5.3 版
本对 5.2 并不是完全兼容。PHP5.3 在 PHP5.2 的基础上做了诸多改进,其中垃圾回收算法
就属于一个比较大的改变。本文将分别讨论 PHP5.2 和 PHP5.3 的垃圾回收机制,并讨论这
种演化和改进对于程序员编写 PHP 的影响以及要注意的问题。
  PHP 变量及关联内存对象的内部表示
  垃圾回收说到底是对变量及其所关联内存对象的操作,所以在讨论 PHP 的垃圾回收
机制之前,先简要介绍 PHP 中变量及其内存对象的内部表示(其 C 源代码中的表示)。
  PHP 官方文档中将 PHP 中的变量划分为两类:标量类型和复杂类型。标量类型包括
布尔型、整型、浮点型和字符串;复杂类型包括数组、对象和资源;还有一个 NULL 比较特殊,
它不划分为任何类型,而是单独成为一类。
  所有这些类型,在 PHP 内部统一用一个叫做 zval 的结构表示,在 PHP 源代码中这个

结构名称为 _zval_struct”。zval 的具体定义在 PHP

源代码的 Zend/zend.h”文件中,下面是

相关代码的摘录。
 
  typedef union _zvalue_value {
  long lval; /* long value */
  double dval; /* double value */
  struct {
  char *val;
  int len;
  } str;
  HashTable *ht; /* hash table value */
  zend_object_value obj;
  } zvalue_value;
  struct _zval_struct {
  /* Variable information */
  zvalue_value value;
  /* value */
  zend_uint refcount__gc;
  zend_uchar type; /* active type */
  zend_uchar is_ref__gc;
  };
 

  其中联合体 _zvalue_value”用于表示 PHP 中所有变量的值,这里之所以使用 union,
是因为一个 zval 在一个时刻只能表示一种类型的变量。可以看到_zvalue_value 中只有 5 个
字段,但是 PHP 中算上 NULL 有 8 种数据类型,那么 PHP 内部是如何用 5 个字段表示 8
种类型呢?这算是 PHP 设计比较巧妙的一个地方,它通过复用字段达到了减少字段的目的。
例如,在 PHP 内部布尔型、整型及资源(只要存储资源的标识符即可)都是通过 lval 字段存
储的;dval 用于存储浮点型;str 存储字符串;ht 存储数组(注意 PHP 中的数组其实是哈希表);
而 obj 存储对象类型;如果所有字段全部置为 0 或 NULL 则表示 PHP 中的 NULL,这样就