实现一个变量,从声明开始到最后没人用,就把这个变量所占的内存给释放掉(垃圾回收);
1:引用计数
2:回收周期
3:性能方面考虑的因素
一、引用计数基本知识
每个php变量存在一个叫“zval”的变量容器中,一个zval变量容器,除了包含变量的类型和值,还包括两个字节的额外信息is_ref和refcount。
1:" is_ref ": bool值,用来标识这个变量是否属于引用集合。
通过这个字节,php引擎才能把普通变量和引用变量区分开来。php允许使用&符号来自定义引用,zval变量容器中还有一个内部引用计数机制来优化内存使用。
2:" refcount ":用来表示指向这个zval变量容器的变量个数。
代码示例:
<?php
1、$name = "hello world";
echo xdebug_debug_zval('name');
输出:name:(refcount = 1,is_ref = 0) = 'hello world';
2、 $name = "hello world";
$temp_name = $name;
xdebug_debug_zval('name');
输出:name:(refcount = 2,is_ref = 0) = 'hello world';
3、 $name = "hello world";
$temp_name = &$name;
xdebug_debug_zval('name');
输出:name:(refcount = 2,is_ref = 1) = 'hello world';
4、$name = 'hello world';
$temp_name = $name;
unset($temp_name);
xdebug_debug_zval('name');
输出:name:(refcount = 1,is_ref = 0) = 'hello world';
5、$name = ['a'=>'hello','b'=>'world'];
xdebug_debug_zval('name');
输出:name: ( refcount=1, is_ref=0) = array (
'a' => (refcount=1, is_ref=0)='hello',
'b' => (refcount=1, is_ref=0)='world'
)
注:unset:当有两个变量指向的时候,unset并非会释放变量所占的内存,只是refcount-1;
【unset只是断开一个变量到一块内存区域的链接,并非会释放内存】
二、回收周期
php如何打开垃圾回收机制?
1、php.ini 中zend.enable_gc = On;
2、gc_enable()和gc_disable()函数来打开和关闭垃圾回收机制;
3、gc_collect_cycles()返回算法回收的周期数, 在节点缓冲区未满的情况下强制执行垃圾分析算法
在这之前,我们应该了解什么叫做垃圾???php中的垃圾是如何定义的?????
如果一个引用计数增加,他将继续被使用,当然就不在垃圾中了;
如果引用计数减少到零时,所在变量容器将会被清除;
其实也就是看refcount是不是等于0了;
言归正传,说回收周期…………
<?php
$a = ['one']; --- zval_a(将$a对应的zval,命名为zval_a)
$a[] = &$a; --- step1
unset($a); --- step2
step1 输出:a: (refcount=2, is_ref=1)
= array (
0 => (refcount=2, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=...)
step2 输出:a: no such symbol
算法总的套路:
大致过程:定义变量->内存增加->清除变量->内存恢复
对于一个包含环形引用的数组,对数组中包含的每个元素的zval进行减1操作,之后如果发现数组自身的zval的refcount变成了0,那么可以判断这个数组是一个垃圾。
三、性能方面
1、实现垃圾回收机制的原因是为了通过清理循环引用的变量来节省内存占用;
2、PHP中的垃圾回收机制,仅仅在循环回收算法确实运行时会有时间消耗上的增加。但是在平常的(更小的)脚本中应根本就没有性能影响。
四、php函数 垃圾回收机制的
1、unset: unset()只是断开一个变量到一块内存区域的链接,同时将该内存区域的refcount-1; 具体的内存是否回收还是要看refcount是否等于0;
2、null: null()是将数据结构置空,同时将refcount变成0;
3、脚本执行结束,该脚本使用的内存都会被释放,不论是否有引用;