上篇文章讲到了PHP的垃圾回收机制,但是引用计数这种垃圾回收机制是无法回收循环引用这种垃圾的,所以在新的版本中,PHP引入了一种新的垃圾回收机制,这个回收机制的具体实现在上文中已经大概讲过了。
当一个变量在被销毁的时候,如果引用计数大于1的话,那么就会将这个变量保存到缓存区中,并且标记为紫色。
当在某个一个点上,有个新的变量被加入到缓存区的时候,并且这个时候缓冲区满了,这个时候就会触发回收机制了。标记回收有一个明显的缺点就是回消耗大量的时候回收,所以通常这个回收机制会导致程序会有几秒到几十秒的卡顿。
这个回收机制是首先,扫描整个缓存区。如果该变量还存在符号表中,则将其设置为黑色。如果不存在符号表中,则将其引用计数减1,同时设置为灰色。
比如下面的数组a:
1、 没加入缓冲区前,数组a引用计数为3
2、 A的引用计数被减1,这个时候为2,判断大于0,加入到缓存区中,并标记为紫色
3、 有新节点加入,缓冲区满了无法加入,触发回收机制
4、 判断a是否在符号表中,是的话标记为黑色。这里a不存在符号表中,所以会遍历a中所有的元素,将a中所有不存在符号表的元素的引用计数都减1。这里a的0和1都不存在符号表中,因此减去两次,就变成了0。同时将a设置为灰色。
5、 再扫描一次缓存区。将引用计数大于0的设置为黑色。
6、 再扫描一次缓存区,将黑色的引用计数恢复加上去1,然后设置为白色。
7、 回收那些不是白色的变量。到这里,a就被回收了。
这里使用这些颜色,我觉得有两个目的:
一来是为了防止重复。比如在将某个变量加入到缓存区的时候,如果这个变量所对应的结构已经被标记为紫色,那么就不用再加入到缓存区中了,因为他已经存在在缓存区了。
二来是为了将其作为状态的转移。