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還原 - 白色:是垃圾,等待後續回收