PHP线程的内存回收问题

 更新时间:2016年07月08日 09:09:42   投稿:hebedich  
本文给大家介绍的是PHP线程的内存回收问题,方便大家理解内存回收的机制,推荐给大家。

当一个PHP线程结束时,当前占用的所有内存空间都会被销毁。那么如果这个线程不结束,怎么回收内存呢?

refcount:引用技术器,可以理解为指向该个容器的指针个数吧。

is_ref:是否被引用(只可能是0或者1)

赋值的流程:

<?php
$a = 'aa';
xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6)
$b = $a; 
//以下的两个其实是一个变量容器
xdebug_debug_zval(a); //(refcount=2, is_ref=0),string 'aa' (length=6)
xdebug_debug_zval(b); //(refcount=2, is_ref=0),string 'aa' (length=6)
unset($b); //对变量容器 refcount 减1
xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6)
xdebug_debug_zval(b); //b: no such symbol b变量被销毁,指向被断掉,如果对应容器的引用技术为零,那么该块儿内存被回收
$b = $a;
$b = 'bb';
xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6)
xdebug_debug_zval(b); //(refcount=1, is_ref=0),string 'aa' (length=6) 重新申请一个变量容器存储b,a的变量容器引用减1

引用的流程:

<?php
$a = 'aa';
xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2)
$b = & $a;
//变量容器的引用技术加1,引用标记置为1
xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('b'); //(refcount=2, is_ref=1),string 'aa' (length=2)
$b = '123'; 
//php会发现,该容器变量是引用(is_ref),所以容器变量不用像赋值那样再申请一个
xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string '123' (length=2)
xdebug_debug_zval('b'); //(refcount=2, is_ref=1),string '123' (length=2)
unset($b);
//变量容器应用计数减1,引用为零
xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string '123' (length=2)
xdebug_debug_zval('b'); // b: no such symbol

那如果多次引用,unset掉一个,is_ref是否会被置为零,那样bug不就出现了么?变量容器还是引用啊。那么我们来看看:

<?php
$a = 'aa';
$b = &$a;
$c = &$a;
//可以看到引用refCount是3,is_ref永远是1
xdebug_debug_zval('a'); //(refcount=3, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('b'); //(refcount=3, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('c'); //(refcount=3, is_ref=1),string 'aa' (length=2)

unset($b);
//我们期待的bug没有出现,只是refcount减1,is_ref还是1
xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('b'); // b: no such symbol
xdebug_debug_zval('c'); //(refcount=2, is_ref=1),string 'aa' (length=2)
//那php它怎么知道这个容器还有引用,毕竟is_ref仍然是1,不能计数,那么现在refcount就起作用了,是它告诉php,该变量有几个引用,但问题又来了,如果我干点坏事,在引用的时候,又赋值,它会不会有bug
$e = $a;
//我们看到期望的bug还是没出现,这时候再赋值,就不像直接赋值那么简单refcount加1了,而是申请了一个新的变量容器
xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('e'); //(refcount=1, is_ref=0),string 'aa' (length=2)

unset和赋值null都能回收变量么?很多人都错认为,这两个都能回收变量空间,其实错了,null只是把变量占用的空间变小了,从回收上来说,该容器依然存在。

<?php
$a = 'aa';
$b = $a;
$b = null;
//又申请了一个变量容器
xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2)
xdebug_debug_zval('b'); //(refcount=1, is_ref=0),null 变量空间并没被回收
unset($b);
//这时候才释放了b变量容器的空间
xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2)
xdebug_debug_zval('b'); //b: no such symbol

总结

1. 垃圾回收的时机

PHP中,引用计数为0,则内存立刻释放。也就是说,不存在环状引用的变量,离开变量的作用域,内存被立刻释放。环状引用检测则是在满足一定条件下触发,所以在上面的例子中,会看到使用的内存有大幅度的波动。也可以通过 gc_collect_cycles 函数来主动进行环状引用检测。

2. &符号的影响

显式引用一个变量,会增加该内存的引用计数:

$a = "something";
$b = &$a;
此时unset($a), 但是仍有$b指向该内存区域的引用,内存不会释放。

3. unset函数的影响

unset只是断开一个变量到一块内存区域的连接,同时将该内存区域的引用计数-1;在上面的例子中,循环体内部,$a=new A(); unset($a);并不会将$a的引用计数减到零;

4. = null 操作的影响;

$a = null 是直接将$a 指向的数据结构置空,同时将其引用计数归0。

5. 脚本执行结束的影响

脚本执行结束,该脚本中使用的所有内存都会被释放,不论是否有引用环。

相关文章

  • PHP 导出数据到淘宝助手CSV的方法分享

    PHP 导出数据到淘宝助手CSV的方法分享

    其中将ECSHOP的数据转到淘宝,原先是有51ecshop开发的ecshop助手有这个功能的,后来我打算自己直接在网页实现,就测试了下了,花了一段时间,共享出来希望对大家有所帮助,可以节省时间。
    2010-02-02
  • PHP去除数组中重复的元素并按键名排序函数

    PHP去除数组中重复的元素并按键名排序函数

    用php实现的去除数组中重复的函数
    2008-08-08
  • php中strtotime函数用法详解

    php中strtotime函数用法详解

    这篇文章主要介绍了php中strtotime函数的用法,以实例形式详细分析了strtotime函数的参数含义与相应的用法,适用于时间格式变换的情况,需要的朋友可以参考下
    2014-11-11
  • Zend Studio (eclipse)使用速度优化方法

    Zend Studio (eclipse)使用速度优化方法

    Zend studio7.12那速度正太让人火大了,修改文件的保存就building workspace,要得等上好一会
    2011-03-03
  • 详解PHP Swoole长连接常见问题

    详解PHP Swoole长连接常见问题

    长连接就是指在基于tcp的通讯中,一直保持连接,不管当前是否发送或者接收数据。本文将详细介绍PHP Swoole长连接的常见问题。
    2021-05-05
  • php+html5+ajax实现上传图片的方法

    php+html5+ajax实现上传图片的方法

    这篇文章主要介绍了php+html5+ajax实现上传图片的方法,对比分析了js原生及jQuery两种ajax调用上传图片的方法,以及php图片上传处理等技巧,需要的朋友可以参考下
    2016-05-05
  • Discuz 模板引擎的封装类代码

    Discuz 模板引擎的封装类代码

    需要使用Discuz的模板引擎,于是周未抽了点时间帮忙做了个封装,测试了一下,速度还不错。顺便也拿来用到自己的程序中使用,欢迎大家下载并提出意见
    2008-07-07
  • 浅谈php安全性需要注意的几点事项

    浅谈php安全性需要注意的几点事项

    这段时间一直在写一个整站,前几天才基本完成了,所以抽个时间写了一篇对于php安全的总结。技术含量不高,过不了也没关系,希望能一些准备写网站的朋友一点引导。
    2014-07-07
  • PHP判断上传文件类型的解决办法

    PHP判断上传文件类型的解决办法

    php通过判断上传文件的头字符来判断文件的类型,这可以称得上是最安全,最真实确定上传文件类型的方法了,具体实现方法如下
    2015-10-10
  • PHP解析RuoYi框架实现Token解密详解

    PHP解析RuoYi框架实现Token解密详解

    这篇文章主要介绍了PHP解析RuoYi框架实现Token解密,同时本篇文章对RuoYi若依框架的使用进行简单的介绍,它和php的fastadmin框架非常类似,是可以根据数据库表自动的生成一个完整的管理后台
    2022-10-10

最新评论