PHP5和PHP7引用对比(笔记)

php5在引入引用计数后,使用了refcount_gc来记录次数,同时使用is_ref_gc来记录是不是引用类型。php

例如php7

$a = 'hello';内存

//$a->zval1(type=IS_STRING,refcount_gc=1,is_ref_gc=0)字符串

这个时候$a指向一个结构体,主要看refcount_gc=1,这就是引用计数字段,由于hello这个字符串被赋值给了$a,因此这个时候hello的引用计数就是1string

$b = $a;引用

$b,$a->zval1(type=IS_STRING,refcount_gc=2,is_ref_gc=0)gc

这个时候又把$a赋值给了$b,因此这个时候$b和$a同时指向这个结构体,而且引用计数加1co

$c = &$b;字符

//$a->zval1(type=IS_STRING,refcount_gc=1,is_ref_gc=0)数字

//$c,$b->zval2(type=IS_STRING,refcount_gc=2,is_ref_gc=1)

这个时候由于把$b赋值给了$c,可是是传址的方式,因此在这个时候就要分离了,$a还指向原来的结构体,$c和$b同时指向一个新的结构体,这个时候zval的is_ref_gc值会改变,使得此时的zval必须进行分离,可是实际上他们的值尚未变化,这使得须要在堆中维护两个值为"hello"的zval。

下面咱们来看看php7中的实现

php7引入了新的类型IS_REFERENCE来处理这个问题,首先看看zend_reference的结构体:

struct _zend_reference{

zend_refcounted_h gc;

zval val;

};

$a = 'hello';

//$a->zend_string(refcount=1,val)

$b = $a;

//$b,$a->zend_string(refcount=2,val)

$c = &$b;

//$a->zend_string(refcount=2,val)

//$c,$b->zval(type=IS_REFERENCE,refcount=2)->zend_string(refcount=2,val)

从上面能够看出来,当使用&操做时,会建立一种新的中间结构体zend_referenct,这个结构体会指向真正的zend_string结构体,因此zend_string结构体的引用计数不变,同时zend_reference结构体的引用计数变为2,由于$c和$b此时的类型都会变为zend_reference,这样的好处是原始的zend_string在内存中始终只有一份(避免了因为字符串的重复申请致使的内存浪费),更加易于维护。

相关文章
相关标签/搜索