PHP最全垃圾回收机制讲解和实测-同时对比PHP5和PHP7

为什么要写这么一篇文章?

网上有很多讲解垃圾回收机制的文章,但是大多数的都是复制,或者停留在PHP5时代。而且很多都是缺乏实际测试而且例子都是同一个例子。所以我想写一篇文章来详细的描述和实战来理解我们的PHP垃圾回收机制。以及PHP5版本下和PHP7版本下的实际测试。

使用什么工具来实测我们的垃圾回收

  • Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具),可以用来跟踪,调试和分析PHP程序的运行状况。Xdebug2018年的最新版本是Xdebug 2.7.0beta1,release日期2018-09-20,添加了对PHP7.2的支持。

我们可以用Xdebug来查看我们变量的引用情况。

首先我们安装Xdebug。

http://xdebug.org/docs/install 这是xdebug官网提供的文档,里面的东西全的一批。我们直接使用perl来安装

pecl install xdebug

在这里插入图片描述
提示这个就是安装成功了,我们需要在ini里面把xdebug这个扩展把它加进去

加好后我们查看php -m
在这里插入图片描述
看到有xdebug说明没问题了。

上面是最新版安装教程

安装老版本

下面我也提供一种方式

https://xdebug.org/download/historical

这里可以看到历史版本的xdebug

我们下载一个适合php5.6版本的xdebug

wget http://xdebug.org/files/xdebug-2.5.1.tgz

Unpack the tarball:

tar -xzf xdebug-3.1.2.tgz

You should not unpack the tarball inside the PHP source code tree. Xdebug is compiled separately, all by itself, as stated above.

cd xdebug-3.1.2

phpize

If phpize is not in your path, please make sure that it is by expanding the PATH environment variable. Make sure you use the phpize that belongs to the PHP version that you want to use Xdebug with. See this FAQ entry if you're having some issues with finding which phpize to use.

./configure --enable-xdebug

make

make install

在这里插入图片描述
直接跑起来 php5.6下面也安装搞定

同样需要在php.ini中去添加扩展

我们了解下官方对于refcount计数是怎么说明的

每个php变量存在一个叫"zval"的变量容器中。一个zval变量容器,除了包含变量的类型和值,还包括两个字节的额外信息。第一个是"is_ref",是个bool值,用来标识这个变量是否是属于引用集合(reference set)。通过这个字节,php引擎才能把普通变量和引用变量区分开来,由于php允许用户通过使用&来使用自定义引用,zval变量容器中还有一个内部引用计数机制,来优化内存使用。第二个额外字节是"refcount",用以表示指向这个zval变量容器的变量(也称符号即symbol)个数。所有的符号存在一个符号表中,其中每个符号都有作用域(scope),那些主脚本(比如:通过浏览器请求的的脚本)和每个函数或者方法也都有作用域。

当一个变量被赋常量值时,就会生成一个zval变量容器

  • refcount加减规则

当任何关联到某个变量容器的变量离开它的作用域(比如:函数执行结束),或者对变量调用了函数 unset()时,”refcount“就会减1
我们首先看一个例子

  • 对于复合类型

当考虑像 array和object这样的复合类型时,事情就稍微有点复杂. 与 标量(scalar)类型的值不同,array和 object类型的变量把它们的成员或属性存在自己的符号表中。这意味着下面的例子将生成三个zval变量容器。

光说不练假把式
我们先在php7版本中来测试引用

  • php7
<?php
$a = 1;
$b = $a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

在这里插入图片描述
这里看到refcount都为0;

  • php5.6环境下测试
    在这里插入图片描述这里看出区别来了吧
    在php5.6 refcount都为2;说明php7对于int类型refcount都不再设置

我们再测试一组代码

<?php
$a = 1;
$b = &$a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

我们使用引用传值方式来看看a和b来看看这个refcount的值为多少。

  • php5.6
    在这里插入图片描述
  • php7
    在这里插入图片描述
    这个时候我们测试的结果是一样的了。(我们这里理解:refcount的值是指向的容器被引用的次数。所以这里a和b的引用次数是一样的

注意:从PHP7的NTS版本开始,引用将不再被计数,即 c = c= c=b=$a之后a的引用计数也是1.具体分类如下:

总共分为三个时间节点

  • php5.3之前:refcount 为0 直接当成垃圾干掉

  • php5.3(包含):(1)如果一个zval的refcount增加,那么此zval还在使用,不属于垃圾

(2)如果一个zval的refcount减少到0, 那么zval可以被释放掉,不属于垃圾

(3)如果一个zval的refcount减少之后大于0,那么此zval还不能被释放,此zval可能成为一个垃圾。

  • php7:在 PHP7 中 zval 有了新的实现方式。最基础的变化就是 zval 需要的内存不再是单独从堆上分配,不再自己存储引用计数。复杂数据类型(比如字符串、数组和对象)的引用计数由其自身来存储。这样就可以有更少的内存分配操作、更少的间接指针使用以及更少的内存分配。

详细php7里面的变化:

在PHP 7中,zval可以被引用计数或不被引用。在zval结构中有一个标志确定了这一点。

对于null,bool,int和double的类型变量,refcount永远不会计数;

② 对于对象、资源类型,refcount计数和php5的一致;

③ 对于字符串,未被引用的变量被称为“实际字符串”。而那些被引用的字符串被重复删除(即只有一个带有特定内容的被插入的字符串)并保证在请求的整个持续时间内存在,所以不需要为它们使用引用计数;如果使用了opcache,这些字符串将存在于共享内存中,在这种情况下,您不能使用引用计数(因为我们的引用计数机制是非原子的);

④对于数组,未引用的变量被称为“不可变数组”。其数组本身计数与php5一致,但是数组里面的每个键值对的计数,则按前面三条的规则(即如果是字符串也不在计数);如果使用opcache,则代码中的常量数组文字将被转换为不可变数组。

在这里插入图片描述

参考文章:https://blog.youkuaiyun.com/cpongo3/article/details/95943464
https://www.cnblogs.com/993089249a/p/13449502.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员若风+

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值