一看就懂系列之 由浅入深聊一聊php的垃圾回收机制 (4)

来个白话文版的: 
例如:

<?php $a = ['one']; --- zval_a(将$a对应的zval,命名为zval_a) $a[] = &$a; --- step1 unset($a); --- step2

1

2

3

4

为进行unset之前(step1),进行算法计算,对这个数组中的所有元素(索引0和索引1)的zval的refcount进行减1操作,由于索引1对应的就是zval_a,所以这个时候zval_a的refcount应该变成了1,这样说明zval_a不是一个垃圾不进行回收。

当执行unset的时候(step2),进行算法计算,由于环形引用,上文得出会有垃圾的结构体,zval_a的refcount是1(zval_a中的索引1指向zval_a),用算法对数组中的所有元素(索引0和索引1)的zval的refcount进行减1操作,这样zval_a的refcount就会变成0,于是就认为zval_a是一个需要回收的垃圾。

算法总的套路:对于一个包含环形引用的数组,对数组中包含的每个元素的zval进行减1操作,之后如果发现数组自身的zval的refcount变成了0,那么可以判断这个数组是一个垃圾。

算法优化配置

可能会发现,每次都进行这样的操作好像会影响性能,是的,php做事情套路都是走批量的原则。

申请内存也是申请一大块,仅使用当前的一小部分剩下的等下回再用,避免多次申请。

这个gc算法也是这样,会有一个缓冲区的概念,等缓冲区满了才会一次性去给清掉。

开关配置

php.ini中设置 zend.enable_gc 项来开启或则关闭GC。

缓冲区配置

缓冲区默认可以放10,000个节点,当缓冲区满了才会清理。可以通过修改Zend/zend_gc.c中的GC_ROOT_BUFFER_MAX_ENTRIES 来改变这个数值,需要重新编译链接PHP

关键函数

gc_enable() : 开启GC

gc_disable() : 关闭GC

gc_collect_cycles() : 在节点缓冲区未满的情况下强制执行垃圾分析算法

涉及到垃圾回收的知识点

1.unset函数

unset只是断开一个变量到一块内存区域的连接,同时将该内存区域的引用计数-1;内存是否回收主要还是看refount是否到0了,以及gc算法判断。

2.= null 操作;

a=nulla=null是直接将a 指向的数据结构置空,同时将其引用计数归0。

3.脚本执行结束

脚本执行结束,该脚本中使用的所有内存都会被释放,不论是否有引用环。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzfggx.html