首页 » 网站建设 » php提醒反复技巧_PHP垃圾收受接收机制

php提醒反复技巧_PHP垃圾收受接收机制

访客 2024-11-24 0

扫一扫用手机浏览

文章目录 [+]

垃圾的产生

之前的文章已经先容过PHP的引用计数机制-PHP内核探索之变量-理解引用,当变量赋值、通报时并不会直接硬拷贝,而是增加value的引用数,unset、return等开释变量时再减掉引用数,减掉后如果创造refcount变为0则直接开释value,这是变量的基本GC(Garbage Collection)过程。

php提醒反复技巧_PHP垃圾收受接收机制

但是在循环引用中,是无法通过这一机制回收变量的。
即当数组或工具内部子元素引用其父元素,而此时如果发生了删除其父元素的情形,此变量容器并不会被删除,由于数组的引用计数中就有一个来自自身成员,试图开释数组时由于其refcount仍旧大于0而得不到开释,而实际上已经没有任何外部引用了,以是无法被打消,因此会发生内存泄露。

php提醒反复技巧_PHP垃圾收受接收机制
(图片来自网络侵删)

下面看一个数组循环引用的例子:

$a = array( 'one' );$a[] = &$a;unset($a);

unset($a)之前的引用关系:

unset($a)之后的引用关系:

可以看到,unset(a)之后由于数组中有子元素指向 a,以是refcount = 1,此时是无法通过正常的gc机制回收的,但是$a已经已经没有任何外部引用了,以是这种变量便是垃圾,垃圾回收器要处理的便是这种情形,这里明确两个准则:

1.如果一个变量value的refcount减少到0, 那么此value可以被开释掉,不属于垃圾

2.如果一个变量value的refcount减少之后大于0,那么此zval还不能被开释,此zval可能成为一个垃圾

针对第一个情形GC不会处理,只有第二种情形GC才会将变量网络起来。
其余变量是否加入垃圾检讨buffer并不是根据zval的类型判断的,是通过zval.u1.type_flag记录的,只有包含IS_TYPE_COLLECTABLE的变量才会被GC网络。

目前垃圾只会涌如今array、object两种类型中,数组的情形上面已经先容了,object的情形则是成员属性引用工具本身导致的,其它类型不会涌现这种变量中的成员引用变量自身的情形,以是垃圾回收只会处理这两种类型的变量。

回收过程

如果当变量的refcount减少后大于0,PHP并不会立即进行对这个变量进行垃圾鉴定,而是放入一个缓冲buffer中,等这个buffer满了往后(默认10000个值)再统一进行处理,加入buffer的是变量zend_value的zend_refcounted_h:

typedef struct _zend_refcounted_h { uint32_t refcount; //记录zend_value的引用数 union { struct { zend_uchar type, //zend_value的类型,与zval.u1.type同等 zend_uchar flags, uint16_t gc_info //GC信息,垃圾回收的过程会用到 } v; uint32_t type_info; } u;} zend_refcounted_h;

一个变量只能加入一次buffer,为了防止重复加入,变量加入后会把zend_refcounted_h.gc_info置为GC_PURPLE,即标为紫色,下次refcount减少时如果创造已经加入过了则不再重复插入。

垃圾缓存区是一个双向链表,等到缓存区满了往后则启动垃圾检讨过程:遍历缓存区,再对当前变量的所有成员进行遍历,然后把成员的refcount减1(如果成员还包含子成员则也进行递归遍历,实在便是深度优先的遍历),末了再检讨当前变量的引用,如果减为了0则为垃圾。
这个算法的事理很大略,垃圾是由于成员引用自身导致的,那么就对所有的成员减一遍引用,结果如果创造变量本身refcount变为了0则就表明其引用全部来自自身成员。
详细的过程如下:

1.从buffer链表的roots开始遍历,把当前value标为灰色(zend_refcounted_h.gc_info置为GC_GREY),然后对当前value的成员进行深度优先遍历,把成员value的refcount减1,并且也标为灰色;

2.重复遍历buffer链表,检讨当前value引用是否为0,为0则表示确实是垃圾,把它标为白色(GC_WHITE),如果不为0则打消了引用全部来自自身成员的可能,表示还有外部的引用,并不是垃圾,这时候由于步骤(1)对成员进行了refcount减1操作,须要再还原回去,对所有成员进行深度遍历,把成员refcount加1,同时标为玄色;

3.再次遍历buffer链表,将非GC_WHITE的节点从roots链表中删除,终极roots链表中全部为真正的垃圾,末了将这些垃圾打消。

垃圾网络的内部实现

接下来我们大略看下垃圾回收的内部实现,垃圾网络器的全局数据构造:

typedef struct _zend_gc_globals { zend_bool gc_enabled; //是否启用gc zend_bool gc_active; //是否在垃圾检讨过程中 zend_bool gc_full; //缓存区是否已满 gc_root_buffer buf; //启动时分配的用于保存可能垃圾的缓存区 gc_root_buffer roots; //指向buf中最新加入的一个可能垃圾 gc_root_buffer unused;//指向buf中没有利用的buffer gc_root_buffer first_unused; //指向buf中第一个没有利用的buffer gc_root_buffer last_unused; //指向buf尾部 gc_root_buffer to_free; //待开释的垃圾 gc_root_buffer next_to_free; uint32_t gc_runs; //统计gc运行次数 uint32_t collected; //统计已回收的垃圾数} zend_gc_globals;typedef struct _gc_root_buffer { zend_refcounted ref; //每个zend_value的gc信息 struct _gc_root_buffer next; struct _gc_root_buffer prev; uint32_t refcount;} gc_root_buffer;

zend_gc_globals是垃圾回收过程中紧张用到的一个构造,用来保存垃圾回收器的所有信息,比如垃圾缓存区;gc_root_buffer用来保存每个可能是垃圾的变量,它实际便是全体垃圾网络buffer链表的元素,当GC网络一个变量时会创建一个gc_root_buffer,插入链表。

zend_gc_globals这个构造中有几个关键成员:

1.buf: 前面已经说过,当refcount减少后如果大于0那么就会将这个变量的value加入GC的垃圾缓存区,buf便是这个缓存区,它实际是一块连续的内存,在GC初始化时一次性分配了10001个gc_root_buffer,插入变量时直接从buf中取出可用节点;

2.roots: 垃圾缓存链表的头部,启动GC检讨的过程便是从roots开始遍历的;

3.first_unused: 指向buf中第一个可用的节点,初始化时这个值为1而不是0,由于第一个gc_root_buffer保留没有利用,有元素插入roots时如果first_unused还没有到达buf的尾部则返回first_unused给最新的元素,然后first_unused++,直到last_unused,比如现在已经加入了2个可能的垃圾变量,则对应的构造:

image.png

4.last_unused: 与first_unused类似,指向buf末端

5.unused: GC网络变量时会依次从buf中获取可用的gc_root_buffer,这种情形直接取first_unused即可,但是有些变量加入垃圾缓存区之后其refcount又减为0了,这种情形就须要从roots中删掉,由于它不可能是垃圾,这样就导致roots链表并不是像buf分配的那样是连续的,中间会涌现一些开始加入后面又删除的节点,这些节点就通过unused串成一个单链表,unused指向链表尾部,下次有新的变量插入roots时优先利用unused的这些节点,其次才是first_unused的,举个例子

//示例1:$a = array(); //$a -> zend_array(refcount=1)$b = $a; //$a -> zend_array(refcount=2) //$b ->unset($b); //此时zend_array(refcount=1),由于refoucnt>0以是加入gc的垃圾缓存区:rootsunset($a); //此时zend_array(refcount=0)且gc_info为GC_PURPLE,则从roots链表中删掉

如果unset($b)时插入的是buf中第1个位置,那么unset(a)后对应的构造:

如果后面再有变量加入GC垃圾缓存区将优先利用第1个。

整理自---《PHP7内核阐发》

标签:

相关文章

介绍皮肤设置,如何打造理想肌肤状态

随着科技的发展和人们对美的追求,皮肤设置已成为美容护肤的重要一环。如何根据皮肤类型、肤质、年龄等因素进行合理设置,已成为众多爱美人...

网站建设 2025-01-03 阅读1 评论0

介绍盖章制作,传承文化,彰显权威

自古以来,盖章在我国文化中具有重要的地位。从古代的官印、私印到现代的公章、合同章,盖章已成为一种独特的文化符号,承载着丰富的历史内...

网站建设 2025-01-03 阅读1 评论0

介绍监控破坏,技术手段与法律风险并存

随着科技的飞速发展,监控设备已遍布大街小巷,成为维护社会治安的重要手段。一些不法分子为了逃避法律制裁,开始研究如何破坏监控设备。本...

网站建设 2025-01-03 阅读1 评论0

介绍登录不上之谜,技术故障还是人为疏忽

随着互联网的普及,登录已成为人们日常生活中不可或缺的一部分。在享受便捷的登录不上这一问题也困扰着许多用户。本文将深入剖析登录不上之...

网站建设 2025-01-03 阅读1 评论0

介绍电脑键盘调出方法,让操作更高效

随着科技的发展,电脑已经成为了我们日常生活中不可或缺的工具。而电脑键盘,作为电脑输入设备,更是我们与电脑进行交流的桥梁。你是否知道...

网站建设 2025-01-03 阅读1 评论0

介绍磁力链,高效便捷的文件下载利器

在互联网高速发展的今天,文件下载已成为日常生活中不可或缺的一部分。而磁力链作为一种新型的文件下载方式,凭借其高效、便捷的特点,受到...

网站建设 2025-01-03 阅读1 评论0