PHP的垃圾回收机制(全网详解)

news2024/10/1 23:29:52

概念:

PHP的垃圾回收机制是自动的,它通过内置的垃圾回收器(Garbage Collector)来实现。当一个PHP对象不再被引用时,它就成为垃圾。垃圾回收器会定期扫描内存中的所有对象,将没有引用的对象标记为垃圾,并释放它们占用的内存空间,以便其他对象可以使用这些空间。

PHP的垃圾回收机制使用了引用计数(reference counting)的算法来跟踪对象的引用情况。每个对象都有一个引用计数器,它记录着对象当前被引用的次数。当一个对象被赋给一个变量时,它的引用计数器会增加1;当一个变量不再引用该对象时,它的引用计数器会减少1。当引用计数器降为0时,这个对象就成为垃圾,垃圾回收器就会释放它所占用的内存。

PHP的垃圾回收机制是自动的,程序员无需手动管理内存。但是,如果程序中存在循环引用的情况,垃圾回收器就无法释放这些对象。为了避免这种情况的发生,PHP提供了一种手动解除引用的方法,即将对象赋值为null,这样就可以让对象的引用计数器降为0,从而被垃圾回收器释放。

一、引用计数基础知识

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

二、生成zval容器

  • 当一个变量被赋常量值时,就会生成一个zval变量容器
  • 如果安装了Xdebug,则可以通过 xdebug_debug_zval() 查看这两个值
<?php
$a = "new string";
xdebug_debug_zval('a');

//结果
a: (refcount=1, is_ref=0)='new string'

三、增加zval的引用计数

把一个变量赋值给另一变量将增加引用次数


<?php
$a = "new string";
$b = $a;
xdebug_debug_zval( 'a' );

//结果
a: (refcount=2, is_ref=0)='new string'

四、减少zval引用计数

  • 使用 unset() 可以减少引用次数 
  • 包含类型和值的这个变量容器就会从内存中删除
<?php
$a = "new string";
$c = $b = $a;
xdebug_debug_zval( 'a' );
unset( $b, $c );
xdebug_debug_zval( 'a' );

//结果
a: (refcount=3, is_ref=0)='new string'
a: (refcount=1, is_ref=0)='new string'

五、复合类型的zval容器

  • 与 标量(scalar)类型的值不同
  • array和 object类型的变量把它们的成员或属性存在自己的符号表中
  • 这意味着下面的例子将生成三个zval变量容器
  • 这三个zval变量容器是: a,meaning和 number


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

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

六、增加复合类型的引用计数

添加一个已经存在的元素到数组中


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

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

七、减少复合类型的引用计数

  • 删除数组中的一个元素
  • 就是类似于从作用域中删除一个变量.
  • 删除后,数组中的这个元素所在的容器的“refcount”值减少

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

//结果
a: (refcount=1, is_ref=0)=array (
'life' => (refcount=1, is_ref=0)='life'
)

八、特殊情况

当我们添加一个数组本身作为这个数组的元素时,事情就变得有趣 

同上,对一个变量调用unset,将删除这个符号,且它指向的变量容器中的引用次数也减1


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

//结果
a: (refcount=2, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=...
)

九、清理变量容器的问题

尽管不再有某个作用域中的任何符号指向这个结构(就是变量容器),由于数组元素“1”仍然指向数组本身,所以这个容器不能被清除 。因为没有另外的符号指向它,用户没有办法清除这个结构,结果就会导致内存泄漏。庆幸的是,php将在脚本执行结束时清除这个数据结构,但是在php清除之前,将耗费不少内存。如果上面的情况发生仅仅一两次倒没什么,但是如果出现几千次,甚至几十万次的内存泄漏,这显然是个大问题

十、回收周期

像以前的 php 用到的引用计数内存机制,无法处理循环的引用内存泄漏

而在php 5.3.0 中使用同步算法,来处理这个内存泄漏问题

如果一个引用计数增加,它将继续被使用,当然就不再在垃圾中。

如果引用计数减少到零,所在变量容器将被清除(free)

就是说,仅仅在引用计数减少到非零值时,才会产生垃圾周期

在一个垃圾周期中,通过检查引用计数是否减1,并且检查哪些变量容器的引用次数是零,来发现哪部分是垃圾

十一、回收算法分析

  • 为避免不得不检查所有引用计数可能减少的垃圾周期
  • 这个算法把所有可能根(possible roots 都是zval变量容器),放在根缓冲区(root buffer)中(用紫色来标记,称为疑似垃圾),这样可以同时确保每个可能的垃圾根(possible garbage root)在缓冲区中只出现一次。仅仅在根缓冲区满了时,才对缓冲区内部所有不同的变量容器执行垃圾回收操作。看上图的步骤 A。
  • 在步骤 B 中,模拟删除每个紫色变量。模拟删除时可能将不是紫色的普通变量引用数减"1",如果某个普通变量引用计数变成0了,就对这个普通变量再做一次模拟删除。每个变量只能被模拟删除一次,模拟删除后标记为灰
  • 在步骤 C 中,模拟恢复每个紫色变量。恢复是有条件的,当变量的引用计数大于0时才对其做模拟恢复。同样每个变量只能恢复一次,恢复后标记为黑,基本就是步骤 B 的逆运算。这样剩下的一堆没能恢复的就是该删除的蓝色节点了,在步骤 D 中遍历出来真的删除掉

十二、性能考虑

主要有两个领域对性能有影响

第一个是内存占用空间的节省

另一个是垃圾回收机制释放已泄漏的内存耗费的时间增加

十三、垃圾回收机制的结论

PHP中的垃圾回收机制,仅仅在循环回收算法确实运行时会有时间消耗上的增加。但是在平常的(更小的)脚本中应根本就没有性能影响。

然而,在平常脚本中有循环回收机制运行的情况下,内存的节省将允许更多这种脚本同时运行在你的服务器上。因为总共使用的内存没达到上限。

这种好处在长时间运行脚本中尤其明显,诸如长时间的测试套件或者daemon脚本此类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/428701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MDK编译过程及文件类型

编译过程 .c和.s文件通过armcc编译器转为.o 其中的code、RO、RW、ZI-data 程序运行时rom中的rw-data复制到SRAM中&#xff0c;SRAM中一般存储可读写的变量&#xff0c;所以ZI-data和RW-data的数据存储在这 经典问题 C语言的全局变量存放在哪里? C语言的全局变量存放在…

HTB-Magic

HTB-Magic信息收集80端口立足www-data -> theseustheseus -> root信息收集 80端口 主页如下。 左下角有一个Login。 抓包后尝试sql注入。 上传一个图片并保存请求。 上传的文件会在/uploads/上传文件名后缀。 只允许我们上传jpg&#xff0c;jpeg&#xff0c;png文…

C/C++每日一练(20230418)

目录 1. 搜索插入位置 &#x1f31f; 2. 最长有效括号 &#x1f31f;&#x1f31f;&#x1f31f; 3. 子集 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏…

2023软件测试银四如何逆势涨薪,开头30秒给你想要的答案

引言 2023软件测试银四逆势涨薪&#xff0c;这是一个让人兴奋的话题。毕竟&#xff0c;在当前就业市场的背景下&#xff0c;很多人正在面临着困境&#xff0c;而能够在逆势中实现薪资上涨的机会&#xff0c;显然是非常值得我们去关注的。 那么&#xff0c;到底是什么让这些软…

C语言实现惯导更新算法(机械编排)

四元数 四元数可用于描述刚体转动或姿态变换,与方向余弦阵相比,表达简洁。四元数是一个包含四个元素的列向量,列向量的第一个元素表示刚体围绕旋转轴转过的角度大小,其余3个元素代表了旋转轴的方向。 姿态更新算法 本程序姿态的递推计算采用四元数来实现,姿态的变化采…

coinex02// 撮合引擎 RingBuffer Disruptor的构建与使用

目录 0. 课程视频地址 0.1 撮合引擎课程 0.1 RocketMQ安装 0.3 RocketMQ搭建成功后登录 1. docker 配置rocketmq 2 逻辑树 : 构建RingBuffer -> 使用RingBuffer 2.1 生产者往RingBuffer中放数据 Disruptor把数据推给消费者cpu 2.2 RingBuffer, Disruptor的创建 ->…

麻了,别再为难测试工程师了...

前言 有不少技术友在测试群里讨论&#xff0c;近期的面试越来越难了&#xff0c;要背的八股文越来越多了,考察得越来越细&#xff0c;越来越底层&#xff0c;明摆着就是想让我们徒手造航母嘛&#xff01;实在是太为难我们这些测试工程师了。 这不&#xff0c;为了帮大家节约时…

Stable Diffusion XL:更快,更强

Stable Diffusion XL&#xff1a;更快&#xff0c;更强 今天&#xff0c;Stability AI 的创始人兼首席执行官 Emad Mostaque 发推宣布&#xff0c;Stable Diffusion XL 进入公测阶段。 核心信息总结起来有2点&#xff1a; “XL”不是新模型的官方名称&#xff0c;Stability …

计算机图形学——游戏方向 第一章 计算机图形学概述

计算机图形学——游戏方向 第一章 计算机图形学概述前言第一章 计算机图形学概述1.为什么设计专业要学习计算机图形学?计算机图形学与计算机视觉等领域的关系计算机图形学基础自学体系2.计算机图形学的辨析3.计算机图形&#xff08;学&#xff09;的发展历史1951&#xff1a;N…

〖Python网络爬虫实战⑭〗- BeautifulSoup详讲

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付费…

Flume系列:Flume Source使用

目录 Apache Hadoop生态-目录汇总-持续更新 1&#xff1a;taildir source 2&#xff1a;kafka source 3&#xff1a;exec source&#xff08;tail -F&#xff09; 4&#xff1a;netcat source&#xff08;采集端口&#xff09; 5&#xff1a;spoolDir读取目录文件&#xf…

Axios请求(对ajax的二次封装)——Axios API、Axios实例、请求配置、Axios响应结构

axios起步——介绍和使用基本用例post请求场景复现核心干货axios APIaxios(config)axios(url[,config])请求方式别名axios实例创建一个axios实例axios.create([config])实例方法axios请求配置axios响应结构场景复现 最近学习与前端相关的小程序时&#xff0c;接触了异步请求ap…

医学图像配准 (Medical Image Registration)

目录 Classification Transformation Registration Algorithms Landmark Based Surfaced Based Voxel Intensity Based Information Theory Based Registration using basis functions Registration using splines Other Physics Based Registration Optimization V…

OctoClock CDA 2990

CDA 2990 CDA 2990为时钟和PPS分发设备&#xff0c;支持外部一路时钟和PPS输入&#xff0c;最高支持8路时钟和PPS输出。同时CDA 2990可选配带GPS模块版本&#xff0c;可外接GPS天线&#xff0c;支持通过GPS锁定时钟和PPS信号输出。CDA 2990主要用于多台USRP设备进行同步。 CDA…

C++之 继承 (inheritance)

目录 启示 一、基本语法 二、继承的方式 三种&#xff1a; 公共基础 / 保护继承 / 私有继承 三、继承中的对象模型 ①父类中所有非静态成员属性都会继承给子类 ②而私有成员属性同样继承过去&#xff0c;但是被编译器隐藏&#xff0c;因此无法访问 四、继承中构造和析…

2023年,送你一份最新的后端架构师知识图谱

这是一个能让你成为架构师的文章&#xff0c;请耐心读完。 为什么写这个 前几天心血来潮搜了下《后端架构师》的技术图谱。发现最新最火的文章更新时间还停留在5年前。最新的技术体系并没有罗列在内。而且文章的颗粒度特别细&#xff0c;是从数据结构和常用算法开始的。这是典…

【加餐 2】Tab 标签页管理

【加餐 2】Tab 标签页管理 对于管理系统,经常需要开启多个标签页,但是每次都需要手动去关闭,很麻烦,所以就有了这个功能,可以一键关闭所有标签页,或者关闭除当前标签页外的所有标签页,对于重要的标签页,可以进行固定至前列,方便下次快速打开。 一、实现效果 实现效…

论文浅尝 | 利用知识图谱增强的Transformer进行跨领域方面抽取

笔记整理&#xff1a;沈小力&#xff0c;东南大学硕士&#xff0c;研究方向为知识图谱链接&#xff1a;https://dl.acm.org/doi/pdf/10.1145/3511808.3557275动机情感分析是自然语言处理的基础任务&#xff0c;它包含介绍了细粒度情感分析中的一个常见任务——基于方面的情感分…

【CSS】鼠标移动到元素上方显示 / 移出盒子范围隐藏案例 ( 子绝父相 | 显示隐藏元素对象 | 鼠标经过样式设置 | 半透明遮罩设置 )

文章目录一、鼠标移动到元素上方显示 / 移出盒子范围隐藏案例要点分析1、子绝父相2、显示隐藏元素对象3、鼠标经过样式设置4、半透明遮罩设置二、代码示例一、鼠标移动到元素上方显示 / 移出盒子范围隐藏案例要点分析 1、子绝父相 这里要 在一个 div 盒子上方套一层遮罩 , 遮罩…

【原理图专题】OrCAD Capture 设计规则(DRC)检查

在原理图设计完成后,需要进行DRC检查,DRC检查能协助工程师快速检查原理图的物理、电气规则是否正确,能快速定位错误和原因。 DRC检查从Capture 工具栏中如下图红框所示的图标中Design Rules Check进入 进入后将打开DRC窗口,有四个选项卡。分别是Design Rules Options、Elec…