php垃圾回收机制

最近在看PHP垃圾回收机制,顺便热蒸现卖,做下总结:

基础概念:写时拷贝 引用计数 回收周期

php的每个变量都会存储在一个叫做zval的变量容器中,这个容器的定义如下:

typedef struct _zval_struct zval;
//zval定义
struct _zval_struct {
	zvalue_value value; /* value*/
	zend_uint refcount__gc;
	zend_uchar type; /* active type */
	zend_uchar is_ref__g
}
//avalue_value定义
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;

在php中,存在8中变量类型,可以分为三类:

  • 标量类型:bool  int  float(double)  string
  • 复合类型:array  object
  • 特殊类型:resource  NULL

在变量声明开始,就会判断数据类型存到zval结构体,结构体的字段解释:

属性名 含义 属性值
refcount_gc 表示变量引用计数 默认1
is_ref_gc 表示是否为引用 bool类型,默认0,用于区别普通变量和引用变量
value 变量的值  
type 变量的内部类型 IS_NULL, IS_BOOL,IS_LONG, IS_DOUBLE, IS_STRING, IS_ARRAY, IS_OBJECT, IS_RESOURCE

介绍完zval结构,我们来说下php是使用变量的时候都做了些什么,我们以php5.6版本和php7.1版本作为比较做以下对比,以此能够看出php不同版本在处理垃圾引用计数上的略微差异:

从以上对比可发现,php5.6和php7.1在变量赋值的时候内存变化是有差异的:

标量:

  • php5.6不会分配新的内存中间,而是将改变量的引用计数加1,而php7.1则分配了一块新的内存中间,并且将b指向它,此时有两个相同的内存变量,他们的引用计数都是1. 
复合变量:
  1. php5.6和php7.1对待数组复合变量的时候也是有差异的,当定义一个一维数组变量arr时,例如demo3,php5.6会生成三个变量,arr,a,b,三个变量的引用计数都是1,而php7.1的arr的引用计数是2;
  2. 当执行$brr=$arr后,php5.6arr引用计数发生变化,而php7.1没有变化;
  3. 当修改$brr的值例如:$brr[a] = 'ddd',则php5.6的arr和brr引用计数都变为1,此时发生了写时拷贝,而arr的引用计数仍为2,brr引用计数为1.就是说php7使用会保持原数组引用计数为2.

数组在循环引用的过程中会造成内存泄漏,具体请看:点击打开链接,所以引入了周期性清理zval容器的问题,引用计数+周期清理能够将php内存泄漏控制在一定范围。

你可能感兴趣的:(php)