baiyan算法
所有视频:https://segmentfault.com/a/11...segmentfault
ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref) { ... if (newRoot) { GC_G(unused) = newRoot->prev; } else if (GC_G(first_unused) != GC_G(last_unused)) { newRoot = GC_G(first_unused); GC_G(first_unused)++; } else { //垃圾回收器存满了,才会启动垃圾回收算法 if (!GC_G(gc_enabled)) { return; } GC_REFCOUNT(ref)++; gc_collect_cycles(); //真正启动垃圾回收算法 GC_REFCOUNT(ref)--; ... } }
ZEND_API int zend_gc_collect_cycles(void) { ... //遍历垃圾回收器链表,若是垃圾回收器链表中的元素是紫色,对其进行深度优先遍历并将refcount减1,并把它们标记为灰色GC_GREY gc_mark_roots(); //遍历垃圾回收器链表,若是垃圾回收器链表中的元素是灰色,那么判断每一个疑似垃圾的元素的refcount是否>0,若是>0就不是垃圾,将其标记为黑色GC_BLACK而且将refcount+1恢复到原来的值;不然为垃圾,将其标记为白色GC_WHITE,它们是真正的垃圾,后面须要释放掉 gc_scan_roots(); ... //把垃圾回收器中为白色GC_WHITE的垃圾单独摘出来放到to_free垃圾链表中,并删除垃圾回收器中不是垃圾的元素 count = gc_collect_roots(&gc_flags); GC_G(gc_active) = 0; if (GC_G(to_free).next == &GC_G(to_free)) { /* 若是垃圾链表to_free为空,那么就没有须要释放的垃圾,直接返回 */ GC_TRACE("Nothing to free"); return 0; } /* 将全局变量中的垃圾链表拷贝到局部变量中 */ to_free.next = GC_G(to_free).next; to_free.prev = GC_G(to_free).prev; to_free.next->prev = &to_free; to_free.prev->next = &to_free; /* 释放全局的垃圾链表 */ GC_G(to_free).next = &GC_G(to_free); GC_G(to_free).prev = &GC_G(to_free); orig_next_to_free = GC_G(next_to_free); ... if (gc_flags & GC_HAS_DESTRUCTORS) { GC_TRACE("Calling destructors"); /* 在析构以前记录引用计数*/ current = to_free.next; while (current != &to_free) { current->refcount = GC_REFCOUNT(current->ref); current = current->next; } /* 析构对象*/ current = to_free.next; while (current != &to_free) { p = current->ref; GC_G(next_to_free) = current->next; if (GC_TYPE(p) == IS_OBJECT) { zend_object *obj = (zend_object*)p; if (!(GC_FLAGS(obj) & IS_OBJ_DESTRUCTOR_CALLED)) { GC_TRACE_REF(obj, "calling destructor"); GC_FLAGS(obj) |= IS_OBJ_DESTRUCTOR_CALLED; if (obj->handlers->dtor_obj && (obj->handlers->dtor_obj != zend_objects_destroy_object || obj->ce->destructor)) { GC_REFCOUNT(obj)++; obj->handlers->dtor_obj(obj); GC_REFCOUNT(obj)--; } } } current = GC_G(next_to_free); } /* 销毁在对象析构过程当中出现的值 */ current = to_free.next; while (current != &to_free) { GC_G(next_to_free) = current->next; if (GC_REFCOUNT(current->ref) > current->refcount) { gc_remove_nested_data_from_buffer(current->ref, current); } current = GC_G(next_to_free); } } /* 销毁zval */ GC_TRACE("Destroying zvals"); GC_G(gc_active) = 1; current = to_free.next; while (current != &to_free) { p = current->ref; GC_G(next_to_free) = current->next; GC_TRACE_REF(p, "destroying"); if (GC_TYPE(p) == IS_OBJECT) { //释放对象 zend_object *obj = (zend_object*)p; EG(objects_store).object_buckets[obj->handle] = SET_OBJ_INVALID(obj); GC_TYPE(obj) = IS_NULL; if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) { GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED; if (obj->handlers->free_obj) { GC_REFCOUNT(obj)++; obj->handlers->free_obj(obj); GC_REFCOUNT(obj)--; } } SET_OBJ_BUCKET_NUMBER(EG(objects_store).object_buckets[obj->handle], EG(objects_store).free_list_head); EG(objects_store).free_list_head = obj->handle; p = current->ref = (zend_refcounted*)(((char*)obj) - obj->handlers->offset); } else if (GC_TYPE(p) == IS_ARRAY) { //释放数组 zend_array *arr = (zend_array*)p; GC_TYPE(arr) = IS_NULL; /* GC may destroy arrays with rc>1. This is valid and safe. */ HT_ALLOW_COW_VIOLATION(arr); zend_hash_destroy(arr); } current = GC_G(next_to_free); } /* 释放垃圾所占用内存空间 */ current = to_free.next; while (current != &to_free) { next = current->next; p = current->ref; if (EXPECTED(current >= GC_G(buf) && current < GC_G(buf) + GC_ROOT_BUFFER_MAX_ENTRIES)) { current->prev = GC_G(unused); GC_G(unused) = current; } efree(p); current = next; } while (GC_G(additional_buffer) != additional_buffer_snapshot) { gc_additional_buffer *next = GC_G(additional_buffer)->next; efree(GC_G(additional_buffer)); //经过efree()释放内存空间 GC_G(additional_buffer) = next; } /* 收尾 */ GC_TRACE("Collection finished"); GC_G(collected) += count; GC_G(next_to_free) = orig_next_to_free; #if ZEND_GC_DEBUG GC_G(gc_full) = orig_gc_full; #endif GC_G(gc_active) = 0; } return count; }
static void gc_mark_roots(void) { gc_root_buffer *current = GC_G(roots).next; while (current != &GC_G(roots)) { if (GC_REF_GET_COLOR(current->ref) == GC_PURPLE) { gc_mark_grey(current->ref); } current = current->next; } }
static void gc_scan_roots(void) { gc_root_buffer *current = GC_G(roots).next; while (current != &GC_G(roots)) { gc_scan(current->ref); //内部还会调用gc_mark_black() current = current->next; } }
- 调用函数gc_mark_roots();首先对垃圾回收器进行深度优先遍历,将refcount-1,并标记为灰色 - 调用函数gc_scan_roots();再次对垃圾回收器进行深度优先遍历,判断当前的refcount,若是大于0,就不是垃圾,标记为黑色,而且要将refcount+1恢复到原来的值;若是等于0,就是垃圾,标记为白色 - 调用函数gc_collect_roots(),将白色的垃圾从垃圾回收器中摘出来,放到垃圾链表中并等待回收;同时将垃圾回收器中不是垃圾的元素移除,以节省垃圾回收器空间 - 释放全局垃圾链表,拷贝到局部垃圾链表,提升效率 - 遍历局部垃圾链表 - 首先析构对象 - 销毁在对象析构过程当中出现的值 - 销毁对象与数组的zval - 释放垃圾所占用内存空间 - 收尾工做
static void gc_mark_grey(zend_refcounted *ref) { HashTable *ht; Bucket *p, *end; zval *zv; tail_call: if (GC_REF_GET_COLOR(ref) != GC_GREY) { ht = NULL; GC_BENCH_INC(zval_marked_grey); GC_REF_SET_COLOR(ref, GC_GREY); if (GC_TYPE(ref) == IS_OBJECT) { zend_object_get_gc_t get_gc; zend_object *obj = (zend_object*)ref; if (EXPECTED(!(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED) && (get_gc = obj->handlers->get_gc) != NULL)) { int n; zval *zv, *end; zval tmp; ZVAL_OBJ(&tmp, obj); ht = get_gc(&tmp, &zv, &n); end = zv + n; if (EXPECTED(!ht)) { if (!n) return; while (!Z_REFCOUNTED_P(--end)) { if (zv == end) return; } } while (zv != end) { if (Z_REFCOUNTED_P(zv)) { ref = Z_COUNTED_P(zv); GC_REFCOUNT(ref)--; gc_mark_grey(ref); } zv++; } if (EXPECTED(!ht)) { ref = Z_COUNTED_P(zv); GC_REFCOUNT(ref)--; goto tail_call; } } else { return; } } else if (GC_TYPE(ref) == IS_ARRAY) { if (((zend_array*)ref) == &EG(symbol_table)) { GC_REF_SET_BLACK(ref); return; } else { ht = (zend_array*)ref; } } else if (GC_TYPE(ref) == IS_REFERENCE) { if (Z_REFCOUNTED(((zend_reference*)ref)->val)) { ref = Z_COUNTED(((zend_reference*)ref)->val); GC_REFCOUNT(ref)--; goto tail_call; } return; } else { return; } if (!ht->nNumUsed) return; p = ht->arData; end = p + ht->nNumUsed; while (1) { end--; zv = &end->val; if (Z_TYPE_P(zv) == IS_INDIRECT) { zv = Z_INDIRECT_P(zv); } if (Z_REFCOUNTED_P(zv)) { break; } if (p == end) return; } while (p != end) { zv = &p->val; if (Z_TYPE_P(zv) == IS_INDIRECT) { zv = Z_INDIRECT_P(zv); } if (Z_REFCOUNTED_P(zv)) { ref = Z_COUNTED_P(zv); GC_REFCOUNT(ref)--; gc_mark_grey(ref); } p++; } zv = &p->val; if (Z_TYPE_P(zv) == IS_INDIRECT) { zv = Z_INDIRECT_P(zv); } ref = Z_COUNTED_P(zv); GC_REFCOUNT(ref)--; goto tail_call; } }
- 紫色:表明该元素已经放入垃圾回收器 - 灰色:表明该元素已经通过了refcount-1的操做 - 黑色:不是垃圾,要将refcount+1还原 - 白色:是垃圾,等待后续回收