什么是垃圾
GC(Garbage Collection)负责清理的垃圾是指:当变量被删除之后,该变量原来连接的容器zval
还存在,导致现在又没有任何变量名指向该zval
。此时该zval
就是需要被回收的垃圾。
什么时候会造成这个情况,可以先了解 PHP 内存泄漏。
生成垃圾
下面配合官方 PHP 垃圾回收 中的配图进行说明。官方文档中的图可能不仔细分析会觉得很难懂,下面我配以一段代码进行说明
$a = "one"; $b = array($a); $b[] = &$b; xdebug_debug_zval('a'); xdebug_debug_zval('b');
打印的结果
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)=..., )
用图表示
这时候unset($b)
就会出现如下情况
这时候原来$b
指向的zval
容器(假设命名为zval_b
)的连接断开了,就导致了内存泄漏,而$a
所指向的zval
容器的连接还存在。zval_b
也就是我们所说的垃圾。那么GC 如何将其识别出来呢?
垃圾回收的实现
1. 上面的zval_b
被视为可能的垃圾存放到根缓存区。
2. 算法会对每个节点(初始节点本身不做减1操作)所包含的zval
进行refcount
模拟减1操作,现在对zval_b
这个容器里的所有节点进行操作,首先对[0]号元素的节点进行模拟减1操作,然后对[1]号元素的节点模拟进行减1操作。只是模拟并不是真正的减1。
3. 算法会对每个节点(初始节点本身不做操作)所包含的refcount > 0
的zval
进行refcount
加1操作,现在对zval_b
这个容器进行操作,[0]号元素的refcount = 0
所以不予以处理,然后对[1]号元素的节点进行加1操作。如此,就确定了垃圾部分,将其标记,同时也对非垃圾进行了还原。
4. 遍历zval_b
节点,将上步中标记成垃圾的节点zval
释放掉。