本文将要讲述 PHP 发展历程中的垃圾回收及内存管理相关内容。
创新互联建站长期为上千多家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为屏边企业提供专业的网站制作、成都网站制作,屏边网站改版等技术服务。拥有10多年丰富建站经验和众多成功案例,为您定制开发。
在 PHP 5.2 及以前的版本中,PHP 的垃圾回收采用的是 引用计数 算法。
引用计数基础知识
php 的变量存储在「zval」变量容器(数据结构)中,「zval」属性包含如下信息:
当一个变量被赋值时,就会生成一个对应的「zavl」变量容器。【推荐学习:PHP视频教程】
要查看变量的「zval」容器信息(即查看变量的 is_ref 和 refcount),可以使用 XDebug 调试工具的 xdebug_debug_zval() 函数。
安装 XDebug 扩展插件的方法可以查看 这个教程(https://github.com/huliuqing/phpnotes/issues/58),有关XDebug 使用方法请阅读 官方文档(https://xdebug.org/docs/)。
假设,我们已经成功安装好 XDebug 工具,现在就可以来对变量进行调试了。
如果我们的 PHP 语句只是对变量进行简单赋值时,is_ref 标识值为 0,refcount 值为 1;若将这个变量作为值赋值给另一个变量时,则增加 zval 变量容器的 refcount 计数;同理,销毁(unset)变量时,「refcount」相应的减去 1。
请看下面的示例:
通过前面的简单变量的 zval 信息我们知道 $copy 和 $name 共用 zval 变量容器(内存),然后通过 refcount 来表示当前这个 zval 被多少个变量使用。
看个实例:
注意到没有,当将值 liugongzi handsome 赋值给变量 $copy 时,name 和 copy 的 refcount 值都变成了 1,在这个过程中发生以下几个操作:
这里只是简单对「写时复制」进行介绍,感兴趣的朋友可以阅读文末给出的参考资料进行更加深入的研究。
引用传值(&)的「引用计数」规则同普通赋值语句一样,只是 is_ref 标识的值为 1 表示该变量是引用传值类型。
我们现在来看看引用传值的示例:
与标量类型(整型、浮点型、布尔型等)不同,数组(array)和对象(object)这种符合类型的引用计数规则会稍复杂一些。
为了更好的说明,还是先看看数组的引用计数示例:
$a = array( 'meaning' => 'life', 'number' => 42 ); xdebug_debug_zval( 'a' ); // a: // (refcount=1, is_ref=0) // array (size=2) // 'meaning' => (refcount=1, is_ref=0)string 'life' (length=4) // 'number' => (refcount=1, is_ref=0)int 42
上面的引用计数示意图如下:
从图中我们发现复合类型的引用计数规则基本上同标量的计数规则一样,就给出的示例来说,PHP 会创建 3 个 zval 变量容器,一个用于存储数组本身,另外两个用于存储数组中的元素。
添加一个已经存在的元素到数组中时,它的引用计数器 refcount 会增加 1。
$a = array( 'meaning' => 'life', 'number' => 42 ); xdebug_debug_zval( 'a' ); $a['life'] = $a['meaning']; xdebug_debug_zval( 'a' ); // a: // (refcount=1, is_ref=0) // array (size=3) // 'meaning' => (refcount=2, is_ref=0)string 'life' (length=4) // 'number' => (refcount=0, is_ref=0)int 42 // 'life' => (refcount=2, is_ref=0)string 'life' (length=4)
大致示意图如下:
虽然,复合类型的引用计数规则同标量类型大致相同,但是如果引用的值为变量自身(即循环应用),在处理不当时,就有可能会造成内存泄露的问题。
让我们来看看下面这个对数组进行引用传值的示例:
从内存占用结果上看,虽然我们执行了 unset($a) 方法来销毁 $a 数组,但内存并没有被回收,整个处理过程的示意图如下:
可以看到对于这块内存,再也没有符合表(变量)指向了,所以 PHP 无法完成内存回收,官方给出的解释如下:
简单来说就是「引用计数」算法无法检测并释放循环引用所使用的内存,最终导致内存泄露。
引用计数系统的同步周期回收
由于引用计数算法存在无法回收循环应用导致的内存泄露问题,在 PHP 5.3 之后对内存回收的实现做了优化,通过采用 引用计数系统的同步周期回收 算法实现内存管理。引用计数系统的同步周期回收算法是一个改良版本的引用计数算法,它在引用基础上做出了如下几个方面的增强:
下图(来自 PHP 手册),展示了新的回收算法执行过程:
整个过程为:
采用深度优先算法执行:默认删除 > 模拟恢复 > 执行删除 达到内存回收的目的。
你可以从 PHP 手册 的回收周期 了解更多,也可以阅读文末给出的参考资料。
PHP 5 中 zval 实现上的主要问题:
PHP 7 中的 zval 数据结构实现的调整:
这种实现的优势:
网页题目:深入讲解PHP垃圾回收及内存管理相关内容
当前地址:http://www.shufengxianlan.com/qtweb/news22/487622.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联