PHP高级学习垃圾收集机制详解
本文阐述了PHP的垃圾收集机制。分享给大家参考,如下:
一.概念
垃圾收集机制是一种动态存储分配方案。它自动释放程序不再需要的已分配内存块。垃圾收集机制可以让程序员不太关注程序内存分配,从而将更多精力投入到业务逻辑上。在流行的语言中,垃圾收集机制是新一代语言的共同特征,如Python、PHP、C#、Ruby等。
二、PHP垃圾收集机制
1.在PHP 5.3版本之前,使用的垃圾收集机制只是简单的“引用计数”。即:每个内存对象分配一个计数器,当内存对象被变量引用时,计数器为1;删除变量引用时(执行unset()后),计数器为-1;当计数器=0时,表示内存对象未被使用,内存对象被销毁,垃圾回收完成。而且PHP会在一个生命周期结束后释放这个进程/线程占用的内容,这就决定了PHP在前期不需要过多考虑内存泄漏的问题。
但是,当两个或两个以上的对象相互引用形成环时,内存对象的计数器不会减少到0;这个时候这组内存对象虽然没用,但是不能回收,导致内存泄漏。从php5.3开始,使用了一种新的垃圾收集机制。基于引用计数,实现了一种复杂的算法来检测内存对象中引用环的存在,以避免内存泄漏。
2.随着PHP的发展,PHP开发人员的增加,业务范围的扩大,在PHP5.3中引入了更加完善的垃圾收集机制,新的垃圾收集机制解决了无法处理周期的引用内存泄漏问题。
正如官方文件所说,每个php变量都存储在一个名为“zval”的变量容器中。除了变量的类型和值之外,zval变量容器还包含两个字节的额外信息。第一个是“is_ref”,这是一个bool值,用于标识该变量是否属于引用集。有了这个字节,php引擎可以区分普通变量和引用变量。因为php允许用户使用自定义引用,所以zval变量容器也有一个内部引用计数机制来优化内存使用。第二个额外的字节是“refcount”,它指示指向这个zval变量容器的变量(也称为符号)的数量。所有符号都存在于符号表中,其中每个符号都有一个范围。下图显示了一个简单的理解:
正如官方文件所说,您可以使用Xdebug来检查引用计数:
?php$a='新字符串';$ c=$ b=$ a;xdebug _ debug _ zval(' a ');联合国索赔集(b,c美元);xdebug _ debug _ zval(' a ');上述例行输出:
a: (refcount=3,is_ref=0)=“新字符串”a: (refcount=1,is_ref=0)=“新字符串”
注意:从NTS版PHP7开始,以上例程的引用将不再计数,即$c=$b=$a后的A的引用计数也为1。具体分类如下:在PHP 7中,zval可以引用也可以不引用。zval结构中有一个标志证实了这一点。(1)对于null、bool、int和double类型的变量,refcount永远不会计数;对于对象和资源类型,refcount计数与php5一致;对于字符串,未引用的变量称为“实际字符串”。但是那些被引用的字符串会被重复删除(也就是只有一个插入的特定内容的字符串),并且保证在整个请求持续时间内存在,所以不需要对它们使用引用计数;如果使用opcache,这些字符串将存在于共享内存中。在这种情况下,您不能使用引用计数(因为我们的引用计数机制是非原子的);对于数组,未引用的变量称为“不可变数组”。数组本身的计数与php5一致,但数组中每个键值对的计数是基于前三个规则的(即如果是字符串就不算);如果使用opcache,代码中的常量数组文本将被转换为不可变数组。同样,这些存在于共享内存中,因此不能使用refcounting。
我们的演示示例如下:
?Phpecho“测试字符串引用计数”;$a=“新字符串”;$ b=$ a;xdebug _ debug _ zval(' a ');联合国索赔集(b美元);xdebug _ debug _ zval(' a ');$ b=$ a;xdebug _ debug _ zval(' a ');Echo“测试数组引用计数”;$c=数组(' a ',' b ');xdebug _ debug _ zval(' c ');$ d=$ c;xdebug _ debug _ zval(' c ');$ c[2]=' c ';xdebug _ debug _ zval(' c ');Echo“测试int类型计数”;$ e=1;xdebug _ debug _ zval(' e ');请参见以下输出:
你可以参考:https://stackoverflow.com/questions/34764119/迷茫-关于-PHP-7-refcount
第三,回收循环
默认情况下,PHP的垃圾收集机制是打开的,然后有一个php.ini设置允许您修改它:zend.enable_gc。
当垃圾收集机制开启时,算法会判断只要根缓冲区满了,就会执行循环搜索。根缓冲区的大小是固定的,默认为10,000。可以通过修改PHP源文件Zend/zend_gc.c中的常量GC_ROOT_BUFFER_MAX_ENTRIES,然后重新编译PHP来修改这个值。当垃圾收集机制关闭时,循环搜索算法将永远不会执行,但是,根将始终存在于根缓冲区中,无论垃圾收集机制是否在配置中被激活。
除了修改配置zend.enable_gc之外,在运行php时还可以通过分别调用gc_enable()和gc_disable()函数来打开和关闭垃圾收集机制。调用这些函数与修改配置项以打开或关闭垃圾收集机制具有相同的效果。即使可能的根缓冲区未满,也可以强制执行循环恢复。您可以调用gc_collect_cycles()函数来实现这个目标。此函数将返回使用此算法恢复的周期数。
允许打开和关闭垃圾收集机制以及允许自主初始化的原因是应用程序的某些部分可能是时间敏感的。在这种情况下,您可能不想使用垃圾收集机制。当然,为应用程序的某些部分关闭垃圾收集机制有可能导致内存泄漏,因为某些可能的根可能没有存储在有限的根缓冲区中。因此,在调用gc_disable()以释放内存之前,调用gc_collect_cycles()可能是明智的。因为这将清除存储在根缓冲区中的所有可能的根,然后当垃圾收集机制关闭时,可以留下一个空缓冲区来有更多的空间来存储可能的根。
四.性能影响
1.节省内存占用空间
首先,实现垃圾收集机制的全部原因是为了在满足前提条件后,通过清理循环引用的变量来节省内存。在PHP执行中,一旦根缓冲区满了或者调用了gc_collect_cycles()函数,就会执行垃圾收集。
2.执行时间会增加
垃圾收集影响性能的第二个方面是释放泄漏内存所需的时间。一般来说,PHP中的垃圾收集机制只会在回收算法确实运行时增加时间消耗。但是在正常的(较小的)脚本中应该不会有任何性能影响。
3.在普通脚本中运行回收机制的情况下,内存的节省将允许更多这样的脚本同时在您的服务器上运行。因为使用的总内存没有达到最大限制。这种优势在长时间运行的脚本中尤其明显,例如长时间运行的测试套件或守护程序脚本。同时,新的垃圾收集机制应该会极大地改变通常运行时间比Web脚本长的脚本应用程序内存泄漏难以解决的观点。
更多对PHP相关内容感兴趣的读者可以查看本网站的话题:《php面向对象程序设计入门教程》、《PHP基本语法入门教程》、《PHP运算与运算符用法总结》、《PHP网络编程技巧总结》、《PHP数组(Array)操作技巧大全》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》、《php常见数据库操作技巧汇总》、0103010。
希望本文对PHP编程有所帮助。
版权声明:PHP高级学习垃圾收集机制详解是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。