php引用计数如何实现垃圾回收

实现说明

1、给对象添加引用计数器,每次在某个地方引用计数器的值都会增加。每当引用失效时,计数器的值就会减一。

变量value的refcount减一后等于0的话,这个value就会被释放,不是垃圾。垃圾回收器不处理。

变量value的refcount减一后大于0以上的话,这个value被认为不能释放,有可能成为垃圾。

2、垃圾回收器收集可能的垃圾,达到一定数量后启动垃圾鉴定程序,释放真正的垃圾。

实例

<?php
//PHP垃圾回收机制案例:参考php手册


//--------------------标量类型--------------------
//tip:每个php变量存在一个叫"zval"的变量容器中,该容器中包含变量的类型和值,"is_ref":是否是引用变量,"refcount":引用计数

//ex:生成一个新的zval容器
$a='newstring';
//ex:显示zval容器信息
xdebug_debug_zval('a');//a:(refcount=1,is_ref=0),string'newstring'(length=10)

//ex:增加zval容器的引用计数
$c=$b=$a;
xdebug_debug_zval('a');//a:(refcount=3,is_ref=0),string'newstring'(length=10)


xdebug_debug_zval('b');//b:(refcount=3,is_ref=0),string'newstring'(length=10)
xdebug_debug_zval('c');//c:(refcount=3,is_ref=0),string'newstring'(length=10)
//tip:此时只有一个容器,因为当没必要时,php不会去复制已生成的变量容器
//此时这个变量容器被变量a,变量b和变量c关联.


unset($b);//ex:减少引用计数
xdebug_debug_zval('a');//a:(refcount=2,is_ref=0),string'newstring'(length=10)
//tip:unset删除变量时,refcount变量计数减一,此时只有$a,$b指向该变量容器


unset($a);
unset($c);
var_dump($a);
//tip:此时recount为0,变量被删除
//当recount变为0时,包含类型和值的这个变量容器就会从内存中删除。


//--------------------复合类型--------------
echo'--------------复合类型------------<br/>';

$a=array(
'name'=>'junior',
'age'=>18
);
xdebug_debug_zval('a');
//a:(refcount=1,is_ref=0),
//array(size=2)
//'name'=>(refcount=1,is_ref=0),string'junior'(length=6)
//'age'=>(refcount=1,is_ref=0),int18


//ex:添加一个已经存在的元素到数组中
$a['love']=$a['name'];
xdebug_debug_zval('a');
//a:(refcount=1,is_ref=0),
//array(size=3)
//'name'=>(refcount=2,is_ref=0),string'junior'(length=6)
//'age'=>(refcount=1,is_ref=0),int18
//'love'=>(refcount=2,is_ref=0),string'junior'(length=6)


//$a=array('one');
//xdebug_debug_zval('a');
////$b=&$a;
//$c=$a;
//$b=&$c;

//xdebug_debug_zval('b');
//xdebug_debug_zval('c');
//xdebug_debug_zval('a');



//清理变量容器问题
echo'------------内存泄漏问题-----------<br/>';
$a=array('one');
xdebug_debug_zval('a');
//a:(refcount=1,is_ref=0),
//array(size=1)
//0=>(refcount=1,is_ref=0),string'one'(length=3)

$a[]=&$a;
xdebug_debug_zval('a');
//a:(refcount=2,is_ref=1),
//array(size=2)
//0=>(refcount=1,is_ref=0),string'one'(length=3)
//1=>(refcount=2,is_ref=1),
//&array

//unset($a);
//(refcount=1,is_ref=1)=array(
//0=>(refcount=1,is_ref=0)='one',
//1=>(refcount=1,is_ref=1)=...
//)

//tip:unset($a)后引用计数减一,尽管不再有某个作用域中的任何符号指向这个结构(就是变量容器),
//由于数组元素"1"仍然指向数组本身,所以这个容器不能被清除
//因为没有另外的符号指向它,用户没有办法清除这个结构,结果就会导致内存泄漏
//庆幸的是,php将在脚本执行结束时清除这个数据结构,但是在php清除之前,将耗费不少内存.
//同样的情况也会发生在对象上,实际上对象更有可能出现这种情况,因为对象总是隐式的被引用。

以上就是php引用计数实现垃圾回收的方法,希望对大家有所帮助。更多php学习指路:php教程

发表回复