- ZEND_API int zend_gc_collect_cycles(void)
- {
- int count = 0;
- if (GC_G(roots).next != &GC_G(roots)) {
- gc_root_buffer *current, *next, *orig_next_to_free;
- zend_refcounted *p;
- gc_root_buffer to_free;
- uint32_t gc_flags = 0;
- gc_additional_buffer *additional_buffer_snapshot;
- #if ZEND_GC_DEBUG
- zend_bool orig_gc_full;
- #endif
- if (GC_G(gc_active)) {
- return 0;
- }
- GC_TRACE("Collecting cycles");
- GC_G(gc_runs)++;
- GC_G(gc_active) = 1;
- GC_TRACE("Marking roots");
- gc_mark_roots();
- GC_TRACE("Scanning roots");
- gc_scan_roots();
- #if ZEND_GC_DEBUG
- orig_gc_full = GC_G(gc_full);
- GC_G(gc_full) = 0;
- #endif
- GC_TRACE("Collecting roots");
- additional_buffer_snapshot = GC_G(additional_buffer);
- count = gc_collect_roots(&gc_flags);
- #if ZEND_GC_DEBUG
- GC_G(gc_full) = orig_gc_full;
- #endif
- GC_G(gc_active) = 0;
- if (GC_G(to_free).next == &GC_G(to_free)) {
- /* nothing to free */
- GC_TRACE("Nothing to free");
- return 0;
- }
- /* Copy global to_free list into local list */
- 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;
- /* Free global list */
- 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 ZEND_GC_DEBUG
- orig_gc_full = GC_G(gc_full);
- GC_G(gc_full) = 0;
- #endif
- if (gc_flags & GC_HAS_DESTRUCTORS) {
- GC_TRACE("Calling destructors");
- /* Remember reference counters before calling destructors */
- current = to_free.next;
- while (current != &to_free) {
- current->refcount = GC_REFCOUNT(current->ref);
- current = current->next;
- }
- /* Call destructors */
- 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);
- }
- /* Remove values captured in destructors */
- 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);
- }
- }
- /* Destroy zvals */
- 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);
- }
- /* Free objects */
- 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));
- 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;
- }
来源: https://www.cnblogs.com/jackson0714/p/9171450.html