搜尋
首頁後端開發php教程php垃圾回收之回收计策和算法

php垃圾回收之回收策略和算法

一、垃圾回收实现方式

? ? ?在以前的php中用到的是引用计数机制处理垃圾回收问题,但是这个机制存在一个弊端,就是无法处理循环引用引起的内存泄露。然而在php5.3.0以后的版本中(包含5.3.0)使用了专门GC机制(同步算法)清理垃圾,来处理这个内存泄露问题。下面就是介绍它是如何实现的:

? ??首先要了解几个基本的准则:

1:如果一个zval的refcount增加,那么此zval还在使用,不属于垃圾。

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

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

? ? ?只有在准则3下,GC才会把zval收集起来,然后通过新的算法来判断此zval是否为垃圾。那么如何判断这么一个变量是否为真正的垃圾呢?简单的说,就是对此zval中的每个元素进行一次refcount减1操作,操作完成之后,如果zval的refcount=0,那么这个zval就是一个垃圾。这个原理咋看起来很简单,但是又不是那么容易理解,下面通过结构图来深入理解:


? ? ?A:为了避免每次变量的refcount减少的时候都调用GC的算法进行垃圾判断,此算法会先把所有前面准则3情况下的zval节点放入一个节点(root)缓冲区(root buffer),并且将这些zval节点标记成紫色,同时算法必须确保每一个zval节点在缓冲区中之出现一次。当缓冲区被节点塞满的时候,GC才开始开始对缓冲区中的zval节点进行垃圾判断。

? ? ?B:当缓冲区满了之后,算法以深度优先对每一个节点所包含的zval进行减1操作,为了确保不会对同一个zval的refcount重复执行减1操作,一旦zval的refcount减1之后会将zval标记成灰色。需要强调的是,这个步骤中,起初节点zval本身不做减1操作,但是如果节点zval中包含的zval又指向了节点zval(环形引用),那么这个时候需要对节点zval进行减1操作。

? ? ?C:算法再次以深度优先判断每一个节点包含的zval的值,如果zval的refcount等于0,那么将其标记成白色(代表垃圾),如果zval的refcount大于0,那么将对此zval以及其包含的zval进行refcount加1操作,这个是对非垃圾的还原操作,同时将这些zval的颜色变成黑色(zval的默认颜色属性)

? ? ?D:遍历zval节点,将C中标记成白色的节点zval释放掉。

二、举例详解垃圾回收过程

? ? ?通过上面的说明,大家可能已经有了一定的印象,那实际应用中是如何具体操作的呢?下面就通过例子说明:

? ? ①在刚刚声明变量并赋值的情况下,其实就相当于准则1(如果一个zval的refcount增加,那么此zval还在使用,不属于垃圾),变量不是垃圾,也不会进行gc检查。

$a = "one";$b = array();$b[] = $a;$b[] = & $b;$c = "two";//声明了三个变量$a、$b、$c。这个时候refcount都是增加的情况,变量不是垃圾也不会放入到root缓冲器等待垃圾检查。xdebug_debug_zval( 'a' );  xdebug_debug_zval( 'b' );  xdebug_debug_zval( 'c' );  //输出分别如下:a: (refcount=2, is_ref=0)='one'b: (refcount=2, is_ref=1)=array (     0 => (refcount=2, is_ref=0)='one',     1 => (refcount=2, is_ref=1)=... )  c: (refcount=1, is_ref=0)='two'

? ?②在上面的基础上,我们调用了unset()函数释放变量b和c。如下:

unset($b);unset($c);xdebug_debug_zval( 'a' ); //输出如下:a: (refcount=2, is_ref=0)='one'

? ? ?调用unset函数后,$b和$c对应容器中的refcount都会减1,但是他们的效果却不相同:先看$c调用unset($c)后,$c的refcount就编程了0,符合准则2,则$c对应的zval容器就是垃圾会被回收;再看$b调用unset($b)后,但是$b的第1个引用仍然指向$b所对应的zval容器,只不过$b对应的zval容器的refcount会减1,值会从2变成1。这时候容器的refcount虽然减1,但仍然不为零,则符合准则3,会把$b对应的zval,放入到root缓冲区中。等待gc垃圾校验操作,也就是进入到了(二)中的(A)情况。

? ? ?③在往后的操作就是(二)中描述的了。经历(二)中的ABCD过程后,变量$b对应的zval容器会被释放,完成了垃圾回收,也解决了循环引用的内存泄露问题。

三、垃圾回收器配置使用

? ? ?在PHP中,GC默认是开启的,你可以通过ini文件中的?zend.enable_gc 项来开启或则关闭GC。当GC开启的时候,垃圾分析算法将在节点缓冲区(roots buffer)满了之后启动。缓冲区默认可以放10,000个值,当然你也可以通过修改Zend/zend_gc.c中的GC_ROOT_BUFFER_MAX_ENTRIES?来改变这个数值,需要重新编译链接PHP。当GC关闭的时候,垃圾分析算法就不会运行,但是相关节点还会被放入节点缓冲区,这个时候如果缓冲区节点已经放满,那么新的节点就不会被记录下来,这些没有被记录下来的节点就永远也不会被垃圾分析算法分析。如果这些节点中有循环引用,那么有可能产生内存泄漏。之所以在GC关闭的时候还要记录这些节点,是因为简单的记录这些节点比在每次产生节点的时候判断GC是否开启更快,另外GC是可以在脚本运行中开启的,所以记录下这些节点,在代码运行的某个时候如果又开启了GC,这些节点就能被分析算法分析。当然垃圾分析算法是一个比较耗时的操作。

??? 在PHP代码中我们可以通过gc_enable()和gc_disable()函数来开启和关闭GC,也可以通过调用gc_collect_cycles()在节点缓冲区未满的情况下强制执行垃圾分析算法。这样用户就可以在程序的某些部分关闭或则开启GC,也可强制进行垃圾分析算法。?

? ? ?

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
以超级用户身份登录Ubuntu以超级用户身份登录UbuntuMar 20, 2024 am 10:55 AM

在Ubuntu系统中,root用户通常是禁用状态的。要激活root用户,可以使用passwd命令设置密码,然后使用su-命令以root身份登录。根用户是具有系统管理权限且不受限制的用户。他拥有访问和修改文件、用户管理、软件安装和删除,以及系统配置更改等权限。根用户与普通用户有着明显的区别,根用户拥有系统中最高的权限和更广泛的控制权。根用户可以执行重要的系统命令和编辑系统文件,而普通用户则无法做到这一点。在本指南中,我将探讨Ubuntu根用户,如何以根用户身份登录,以及它与普通用户的不同之处。注意

Nginx配置中指令root和alias的区别是什么Nginx配置中指令root和alias的区别是什么May 12, 2023 pm 12:16 PM

root和alias都可以定义在location模块中,都是用来指定请求资源的真实路径,比如:location/i/{root/data/w3;}请求http://foofish.net/i/top.gif这个地址时,那么在服务器里面对应的真正的资源是/data/w3/i/top.gif文件注意:真实的路径是root指定的值加上location指定的值。而alias正如其名,alias指定的路径是location的别名,不管location的值怎么写,资源的真实路径都是alias指定的路径,比如

手把手使用 Python 删除 Windows 下的长路径文件手把手使用 Python 删除 Windows 下的长路径文件Apr 12, 2023 pm 01:31 PM

0x01 文章背景近期,笔者所在公司的某业务系统的存储临近极限,服务器马上就要跑不动了,由于该业务系统A包含多个子系统A1、A2、A3 ... An,这些子系统的中间存储文件由于设计原因,都存储在同一个父级目录之内,唯一不同的是,不同子系统产生的文件和文件夹的名字都以该子系统名开始。如A1子系统产生的文件命名方式均为A1xxxxxx​, A2子系统产生的文件名均为A2xxxxx。现在要删除其中一些子系统的历史文件,以释放服务器空间,几十T的数据,存放在一起,手动删除肯定不显示,只能借助程序自动化

Linux怎么修改root用户名称Linux怎么修改root用户名称May 18, 2023 pm 07:50 PM

1、以CentOS为例,登录后修改/etc/passwd与/etc/shadow,将第一行开始的root改为新的用户名(比如admin),修改之后通过wq!保存。2、修改并保存后,重启服务器后即可生效,可以看下文件的权限,可以看到所属帐号一栏变为admin了,如下:注:在Linux中默认的最高管理权限用户是root,uid为0。在系统中只识别uid,因此只要uid为0,系统就视为最高管理用户。但是对于应用程序可能会存在一定的问题,有些软件默认使用的是root用户,所以在对软件应用的了解有限的情况

手机root的好处和坏处手机root的好处和坏处Jul 06, 2023 pm 04:53 PM

手机root的好处:1、可以备份系统;2、可以使用高级的程序;3、可以修改和删除系统的程序;4、可以把程序安装在sd卡上;5、可以修改系统字体等等。坏处:1、手机root后容易被木马病毒侵入;2、可能因为不彻底以及软件兼容性等问题,导致系统损坏出现系统运行问题;3、手机root后软件错删系统文件导致系统错误;4、手机root后用户隐私有被泄露风险等等。

在生产服务器上启用XDebug会使PHP变慢吗?在生产服务器上启用XDebug会使PHP变慢吗?Sep 22, 2023 pm 10:41 PM

是的,像XDebug这样的调试器会降低PHP服务器的性能。这就是调试器不放置在服务器环境中的原因。它们部署在不同的环境中,以避免不必要的开销。调试消息无法在已处于生产阶段的应用程序中显示。当将调试行为添加到服务器上,调试引擎附加到PHP进程。它开始接收消息以在断点处停止,但这不是必需的行为,因为它会给其他进程带来高性能打击,从而停止PHP解析器。另一方面,当调试器安装后,它们往往会在服务器中打开端口,因为它们不打算在生产环境中使用。在服务器中打开端口就像为黑客打开一扇窥探之门一样糟糕。

PHP是如何存储变量的?zval结构体你了解吗?PHP是如何存储变量的?zval结构体你了解吗?May 26, 2022 am 09:47 AM

在 PHP 中定义一个变量是不需要声明类型的,一开始给变量 $a 赋予一个整型值,后面又可以轻而易举地将其改变为其他类型。那在 PHP 的源码中是如何来存储这个变量 $a 的呢?带着这个疑问我们一起去看一看 PHP 的源码。

非root权限下安装Linux程序的方法非root权限下安装Linux程序的方法Jan 13, 2024 pm 03:27 PM

对于一些共用的机器,可能我们并没有root权限,在安装程序时会稍微麻烦点,其实只要把相关文件放在自己的目录下就可以免去root权限限制了。我装libevent,无root权限,通过prefix指定安装路径为我的/home目录下即可:./configure--prefix=/home/****/libevent--enable-sharedmakemakeinstallmakeverify#libevent的测试,其他的安装不一定有。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
2 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
2 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版