php garbage collection related

After reading several articles about php garbage collection and the changes of php5.3~php7, I personally summarize a few points. It is mainly summarized from the changes in the variable structure and the changes in the garbage collection mechanism:

1. Variables

At
the stage of php5.3~php7 , the definition of variables is divided into

zval_struct {
    
    zval_value value;
    zend_uint ref_count_gc;
    zend_uchar is_ref_gc;
    zend_uchar type;
}
zvalue_value {
    long;
    double;
    struct {

    } str;
    Hashtable * ht;
    zend_obj_val obj;
}

Hashtable :
zend_array {
    zend_refcount_h gc;
    ....(那串复杂的结构,包括了 bucket *arData等)
}

php7 is integrated into a data structure, and the reference count is a structure

typedef struct _zend_refcounted_h {
    uint32_t         refcount; // 记录 zend_value 的引用数
    union {
        struct {
            zend_uchar    type,  // zend_value的类型, 与zval.u1.type一致
            zend_uchar    flags, 
            uint16_t      gc_info // GC信息,记录在 gc 池中的位置和颜色,垃圾回收的过程会用到
        } v;
        uint32_t type_info;
    } u;
} zend_refcounted_h;

 

2. Garbage collection mechanism
1. Based on PHP's reference counting mechanism (the only mechanism before PHP 5.3)
2. At the same time, use the root buffer mechanism. When PHP finds a circular reference zval, it will invest it in Root buffer, when the root buffer reaches the specified number in the configuration file, it will be garbage collected to solve the memory leak caused by circular references (php5.3 began to introduce this mechanism)
3. php7 uses three marks

other instructions:

1. The position of refcount in php7 has also been moved from the zval structure to zval_value, so not all data types will have reference counting operations, such as integer, floating point, Boolean, NULL, these simple data types have no refcount
2. The algorithm used by php5.3~7 garbage collection:
Only the circularly referenced zval will be put into the buffer (the specific condition is: if the refcount of the variable is reduced and greater than 0, PHP will not immediately This variable is garbage identified and recycled, but put into a buffer ), and a reference count of 1 in the buffer means that there is no symbol in the current scope pointing to the zval, that is, garbage that should be recycled.
Therefore, whenever the root buffer is full, php will traverse all the variable containers in the root buffer for simulated deletion, and will perform simulated recovery after simulated deletion. But php will only restore the refcount>0 after the simulated deletion, then there is no way to restore the refcount=0, which is garbage~

3. The garbage collection of php7 uses three-color marking:

Process description:

A variable can only be added to the buffer once. In order to prevent repeated addition, zend_refcounted_h.gc_info will be set to GC_PURPLE after the variable is added, that is, it will be marked as purple, and it will not be inserted repeatedly in the future.

The garbage buffer is a doubly linked list. After the buffer is full, the garbage check process is started: traverse the buffer, traverse all the members of the current variable, and then decrement the refcount of the member by 1 (if the member also contains sub-members, it is also performed Recursive traversal, that is, depth-first traversal), and finally check the reference of the current variable, if it is reduced to 0, it is garbage. The core principle of this algorithm is: garbage is caused by members referencing themselves, then all members are decremented. If it is found that the refcount of the variable itself becomes 0, it means that all references are from its own members, that is, anywhere else. No longer use it, then it is garbage and needs to be recycled. On the contrary, it is not garbage and needs to be removed from the buffer. The specific process is as follows:

(1) Start traversal from the roots of the buffer linked list, mark the current value in gray (zend_refcounted_h.gc_info is set to GC_GREY), and then perform a depth-first traversal on the members of the current value, reduce the refcount of the member value by 1, and also mark it as gray;

(2) Repeatedly traverse the buffer list, check whether the current value reference is 0, if it is 0, it is indeed garbage, and mark it as white (GC_WHITE), if it is not 0, it excludes the possibility that all references come from its own members, which means There are also external references, which are not rubbish. At this time, because step (1) has performed the refcount minus 1 operation on the member, it needs to be restored again, and all members are traversed in depth, and the member refcount is increased by 1 and marked as black at the same time;

(3) Traverse the buffer linked list again, remove the nodes that are not GC_WHITE from the roots linked list, and finally all the real garbage in the roots linked list, and finally remove these garbage.

From: https://learnku.com/articles/33451

Guess you like

Origin blog.csdn.net/jayxujia123/article/details/115049850