垃圾回收是一种自动的内存管理机制,当一个变量在程序中不再被使用时,应该予以释放,这种内存资源管理称为垃圾回收。其中一种垃圾回收方式是使用引用计数,通过对数据存储的物理空间多附加一个计数器空间,当其他数据与其相关是,计数器加一,反之,相关解除时计数器减一。定期检查各存储对象的计数器,计数器为零的话,则认为该对象已经被抛弃而应将其所占物理空间回收。
下面是GC的核心数据结构:
1 | struct _zend_refcounted { |
zend_refcounted由32位bit的refcount和32bit的type_info组成
1. type 第一个字节记录当前元素的类型
flags 第二个字节用来记录数据类型
gc_info 后面的两个字节标记当前元素的颜色和垃圾回收池中的位置,其中高地址的两位用来标记颜色。
3.1 颜色有 黑色,白色,灰色,紫色
php性能提升
gc垃圾收集器
下面是gc_globals的结构
gc_root_buffer 是一个双向链表,同时记录引用计数的相关信息,zend_gc_globals维护者gc的整个信息,这里列出个字段的含义。
序号 | 字段 | 含义 |
---|---|---|
1 | gc_enabled | 是否开启gc |
2 | gc_active | 垃圾回收算法是否运行 |
3 | gc_full | 垃圾缓冲区是否满了,在debug模式下有用 |
4 | buf | 垃圾缓冲区,PHP7默认大小为10 000个节点位置,0位置保留 |
5 | roots | 指向缓冲区中最新加入的可能是垃圾的元素 |
6 | unused | 指向缓冲区中没有使用的位置,在没有启动垃圾回收算法前,指向空 |
7 | first_unused | 指向缓冲区中第一个未使用的位置,新的元素插入缓冲区后,指针会后移动一位 |
8 | last_unused | 指向缓冲区中最后一个位置 |
9 | to_free | 待释放的列表 |
10 | next_to_free | 下一个待释放的列表 |
11 | gc_runs | 记录gc算法的运行的次数,当缓冲区满了,才会运行gc算法 |
12 | collected | 记录gc算法回收的垃圾数 |
垃圾收集过程
- 要求数据类型是数组和对象
- 没有在缓冲区中存在过
- 没有被标记过
- 将其gc_info标记为紫色的,且记录其在缓冲区的位置
当缓冲区满时,再收集新的元素会出发垃圾回收算法。
垃圾流转图:
回收过程分为4部分
对roots环中每一个元素进行深度优先遍历,将每个元素中gc_info为紫色的标记元素为灰色,且引用计数-1
扫描roots换中gc_info为灰色的元素,如果发现引用计数仍旧大于0,说明这个元素在其他地方使用,那么将其颜色重新标记为黑色,如果发现其引用计数是0则将其标记为白色,该过程同样为深度优先遍历。
扫描roots换,将gc_info颜色为黑色的的元素从roots移除,然后对roots中颜色为白色的元素进行深度有限遍历,将其引用计数+1,然后将roots链表移动到待释放列表中(to_free)中等待回收