PHP的垃圾回收机制代码实例讲解


Posted in PHP onFebruary 27, 2021

PHP可以自动进行内存管理,清除不需要的对象,主要使用了引用计数

zval结构体中定义了ref_countis_ref , ref_count是引用计数 ,标识此zval被多少个变量引用 , 为0时会被销毁
is_ref标识是否使用的 &取地址符强制引用

为了解决循环引用内存泄露问题 , 使用同步周期回收算法
比如当数组或对象循环的引用自身 , unset掉数组的时候 , 当refcount-1后还大于0的 , 就会被当成疑似垃圾 , 会进行遍历 ,并且模拟的删除一次refcount-1如果是0就删除 ,如果不是0就恢复

顽固垃圾的产生过程

<?php
  $a = "new string";
?>

代码中,$a变量内部存储信息为

a: (refcount_gc=1, is_ref_gc=0)='new string'

当把 a 赋 值 给 另 外 一 个 变 量 的 时 候 , a赋值给另外一个变量的时候, a赋值给另外一个变量的时候,a对应的zval的refcount_gc会加1

<?php
  $a = "new string";
  $b = $a;
?>

此时 a 和 a和 a和b变量对应的内部存储信息为, a 和 a和 a和b同时指向一个字符串"new string" ,它的refcount变成2

a,b: (refcount_gc=2, is_ref=0)='new string'

当用unset删除$b变量时,“new string” 的refcount_gc会减1变成1。

<?php
  $a = "new string"; //a: (refcount_gc=1, is_ref_gc=0)='new string'
  $b = $a;      //a,b: (refcount_gc=2, is_ref=0)='new string'
  unset($b);     //a: (refcount_gc=1, is_ref=0)='new string'
?>

对于普通的变量来说,这一切很正常,但是在复合类型变量(数组和对象)中,会发生比较有意思的事情:

<?php
  $a = array('meaning' => 'life', 'number' => 42);
?>

$a内部存储信息为:

a: (refcount=1, is_ref=0)=array (
'meaning' => (refcount=1, is_ref=0)='life',
'number' => (refcount=1, is_ref=0)=42
)

数组变量本身($a)在引擎内部实际上是一个哈希表,这张表中有两个zval项 meaning和number,所以实际上那一行代码中一共生成了3个zval,这3个zval都遵循变量的引用和计数原则,用图来表示:
PHP的垃圾回收机制代码实例讲解

下面在$a中添加一个元素,并将现有的一个元素的值赋给新的元素:

<?php
  $a = array('meaning' => 'life', 'number' => 42);
  $a['name'] = $a['meaning'];
?>

那么$a的内部存储为 , “life” 的ref_count变成2 , 42的ref_count是1:

a: (refcount=1, is_ref=0)=array (
'meaning' => (refcount=2, is_ref=0)='life',
'number' => (refcount=1, is_ref=0)=42,
'name' => (refcount=2, is_ref=0)='life'
)

如果将数组的引用赋值给数组中的一个元素,有意思的事情就会发生:

<?php
  $a = array('one');
  $a[] = &$a;
?>

这样 a 数 组 就 有 两 个 元 素 , 一 个 索 引 为 0 , 值 为 字 符 o n e , 另 外 一 个 索 引 为 1 , 为 a数组就有两个元素,一个索引为0,值为字符one,另外一个索引为1,为 a数组就有两个元素,一个索引为0,值为字符one,另外一个索引为1,为a自身的引用,内部存储如下:
PHP的垃圾回收机制代码实例讲解

a: (refcount=2, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=…
)

array这个zvalref_count是2 , 是一个环形引用
这时对$a进行unset,那么 a 会 从 符 号 表 中 删 除 , 同 时 ‘ a会从符号表中删除,同时` a会从符号表中删除,同时‘a指向的zvalrefcount_gc`减少1.

<?php
$a = array('one');
$a[] = &$a;
unset($a);
?>

那么问题就产生了, a 已 经 不 在 符 号 表 中 , 用 户 无 法 再 访 问 此 变 量 , 但 是 a已经不在符号表中,用户无法再访问此变量,但是 a已经不在符号表中,用户无法再访问此变量,但是a之前指向的zval的refcount_gc变为1而不是0,因此不能被回收,从而产生内存泄露,新的GC要做的工作就是清理此类垃圾。

为了解决循环引用内存泄露问题 , 使用同步周期回收算法 , 这种ref_count减1后还大于0的会被作为疑似垃圾

比如当数组或对象循环的引用自身 , unset掉数组的时候 , 当refcount-1后还大于0的 , 会进行遍历 ,并且模拟的删除一次refcount-1如果是0就删除 ,如果不是0就恢复。

到此这篇关于PHP的垃圾回收机制代码实例讲解的文章就介绍到这了,更多相关PHP的垃圾回收机制内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PHP 相关文章推荐
建立动态的WML站点(三)
Oct 09 PHP
可以在线执行PHP代码包装修正版
Mar 15 PHP
用C/C++扩展你的PHP 为你的php增加功能
Sep 06 PHP
php+mysqli数据库连接的两种方式
Jan 28 PHP
在Debian系统下配置LNMP的教程
Jul 09 PHP
Symfony2 session用法实例分析
Feb 04 PHP
Yii2使用自带的UploadedFile实现的文件上传
Jun 20 PHP
详解Yaf框架PHPUnit集成测试方法
Dec 27 PHP
PHP异常类及异常处理操作实例详解
Dec 19 PHP
Laravel 错误提示本地化的实现
Oct 22 PHP
laravel5.6 框架操作数据 Eloquent ORM用法示例
Jan 26 PHP
Swoole扩展的6种模式深入详解
Mar 04 PHP
php命令行模式代码实例详解
Feb 26 #PHP
PHP时间类完整代码实例
Feb 26 #PHP
PHP队列场景以及实现代码实例详解
Feb 26 #PHP
PHP实现长轮询消息实时推送功能代码实例讲解
Feb 26 #PHP
php的对象传值与引用传值代码实例讲解
Feb 26 #PHP
php并发加锁问题分析与设计代码实例讲解
Feb 26 #PHP
PHP内存溢出优化代码详解
Feb 26 #PHP
You might like
DIY一个适配电脑声卡的动圈话筒放大器
2021/03/02 无线电
咖啡历史、消费和行业趋势
2021/03/03 咖啡文化
PHP配置文件中最常用四个ini函数
2007/03/19 PHP
PHP Session变量不能传送到下一页的解决方法
2009/11/27 PHP
搭建基于Docker的PHP开发环境的详细教程
2015/07/01 PHP
php微信开发之图片回复功能
2018/06/14 PHP
js类中获取外部函数名的方法
2007/08/19 Javascript
javascript时间自动刷新实现原理与步骤
2013/01/06 Javascript
顶部缓冲下拉菜单导航特效的JS代码
2013/08/27 Javascript
js中的referrer返回上一页使用介绍
2013/09/26 Javascript
Javascript函数式编程语言
2015/10/11 Javascript
jquery实现下拉框多选方法介绍
2017/01/03 Javascript
[js高手之路]寄生组合式继承的优势详解
2017/08/28 Javascript
js实现鼠标跟随运动效果
2020/08/02 Javascript
ztree加载完成后显示勾选节点的实现代码
2018/10/22 Javascript
Vue实现移动端页面切换效果【推荐】
2018/11/13 Javascript
uni-app实现点赞评论功能
2019/11/25 Javascript
vue.js使用v-model实现父子组件间的双向通信示例
2020/02/05 Javascript
Python中使用Inotify监控文件实例
2015/02/14 Python
Python中实现结构相似的函数调用方法
2015/03/10 Python
从CentOS安装完成到生成词云python的实例
2017/12/01 Python
Python生成器以及应用实例解析
2018/02/08 Python
使用anaconda的pip安装第三方python包的操作步骤
2018/06/11 Python
浅谈Pycharm调用同级目录下的py脚本bug
2018/12/03 Python
python tkinter图形界面代码统计工具(更新)
2019/09/18 Python
Jupyter Notebook 文件默认目录的查看以及更改步骤
2020/04/14 Python
python matplotlib工具栏源码探析二之添加、删除内置工具项的案例
2021/02/25 Python
印度购物网站:TATA CLiQ
2017/11/23 全球购物
求职自荐书范文
2013/12/04 职场文书
最新的互联网创业计划书
2014/01/10 职场文书
初二物理教学反思
2014/01/29 职场文书
药学专业学生的自我评价分享
2014/02/06 职场文书
互联网创业计划书写作技巧攻略
2014/03/23 职场文书
后勤个人工作总结
2015/02/28 职场文书
《半截蜡烛》教学反思
2016/02/19 职场文书
100句拼搏进取的名言警句,值得一读!
2019/10/07 职场文书