手机版

PHP7垃圾收集机制分析

时间:2021-08-20 来源:互联网 编辑:宝哥软件园 浏览:

垃圾收集机制

垃圾收集机制是一种动态存储分配方案。它自动释放程序不再需要的已分配内存块。自动回收内存的过程称为垃圾回收。垃圾收集机制可以让程序员不太关注程序内存分配,从而将更多精力投入到业务逻辑上。在流行的语言中,垃圾收集机制是新一代语言的共同特征。

垃圾的产生

在PHP7中复杂类型的数据结构中,如字符串、数组、对象等。标头中有一个gc,用于支持垃圾收集。当一个变量被赋值和传递时,它将增加引用值的数量。取消设置、返回等。释放变量时将减去参考数字。减去后,如果refcount变为0,将直接释放该值,这是变量的基本回收过程。

但是,有一个问题是这种机制无法解决的,那就是循环引用的问题。

什么是循环引用?简单来说,变量中存储的值是指变量本身。这种比较经常发生在数组和对象类型的变量上。

先说引用,也就是zend_reference,这是PHP7中一个新的变量类型。当您对变量使用“”操作时,您将创建一个新的中间结构zend_reference,它将真正指向相应的值结构。

例如:

//$a='hello '执行以下赋值操作时;//$ a-Zend _ string $ b=$ a;//$b,$ a-Zend _ string $ c=$ b;//$c,$b - zval(类型=IS_REFERENCE,refcount=2) - zend_string

最终会变成这样:

也就是说,$b和$c的zval通过中间结构zend_reference指向最终的zend_string。

回到循环引用的问题,举一个数组循环引用的例子:

$ arr=[1];$ a[]=$ a;联合国索赔集(美元);使用该操作后,变量A变成引用类型,引用计数refcount为2,赋给自身内部的元素,即变量A变成自身引用自身。

详情如下:

取消设置后,它会变成这样:

也就是说$a所在的zval类型已经改为IS_UNDEF,zend_reference结构的引用计数减少1,但仍然大于0。这时,这部分结构就变成了垃圾,如果不处理,可能会造成内存泄漏。在这里,我们需要垃圾收集器将这一部分收集到缓冲区中,然后回收它。

恢复过程

如果一个变量缩减后的refcount大于0,PHP不会立即识别并回收这个变量,而是放入一个缓冲区,当缓冲区满了(10,000个值)后,会统一处理。变量zend_value中的gc被添加到缓冲区中。目前垃圾只出现在数组和对象两种类型。上面已经描述了阵列的情况。对象的情况是由引用对象本身的成员属性引起的,其他类型不会有这个变量中的成员引用变量本身的情况,所以垃圾收集只会处理这两类变量。

gc结构zend_refcounted_h如下:

typedef struct _ Zend _ ref count _ h { uint 32 _ t ref count;//记录Zend _ value union { struct { Zend _ uchart type,//Zend _ value type,与zval.u1.type,Zend _ ucharflags,uint16 _ tgc _ info//gc信息一致的引用号,记录gc池中的位置和颜色,垃圾收集时使用} v;uint32 _ t type _ info} u;} Zend _ ref count _ h;一个变量只能添加到缓冲区一次。为了防止重复添加,变量添加后zend _ refcounted _ h.gc _ info将被设置为GC _紫色,即标记为紫色,后续的插入不会重复。

垃圾缓冲区是一个双向链表。当缓冲区已满时,垃圾检查过程开始:遍历缓冲区,遍历当前变量的所有成员,然后将成员的refcount减少1(如果成员也包含子成员,则递归遍历,即深度优先遍历),最后检查当前变量的引用。如果降为0,就是垃圾。这个算法的原理核心是:垃圾是成员引用自己造成的,所以引用中减去所有成员。如果最后发现变量本身的refcount变成了0,说明它所有的引用都来自于自己的成员,也就是说其他地方不再使用,所以是垃圾,需要回收。相反,这意味着它不是垃圾,需要从缓冲区中移除。具体流程如下:

(1)从缓冲链表的根遍历,将当前值标记为gray(Zend _ ref count _ h . GC _ info标记为GC_GREY),然后先深度遍历当前值的成员,将成员值的refcount减1,标记为gray;

(2)反复遍历缓冲区链表,检查当前值引用是否为0,如果为0则表示真的是垃圾,标记为WHITE(GC _ WHITE);如果不是0,则排除了所有引用都来自其自身成员的可能性,表示存在外部引用,而不是垃圾。此时,因为步骤(1)中成员的refcount减少了1,所以需要再次恢复,并且所有成员都被深度遍历以进行refcount

(3)再次遍历缓冲区链表,将非GC_WHITE节点移出根链表(移至待释放的列表),最后所有的根链表都是真正的垃圾,最后清除垃圾。

摘要

以上是边肖介绍的PHP7的垃圾收集机制,希望对大家有所帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!如果你觉得这篇文章对你有帮助,请转载,请注明出处,谢谢!

版权声明:PHP7垃圾收集机制分析是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。