This article mainly introduces about the PHP source code 34: PHP5.3 New garbage collection mechanism (garbage Collection), has a certain reference value, now share to everyone, the need for friends can refer to
A brief talk on PHP source 34: PHP5.3 New garbage collection mechanism (garbage Collection)
In the previous article on PHP source 33: PHP5.3 A new addition to the garbage collection mechanism (garbage Collection), the basic knowledge of garbage collection mechanism is introduced. Today we look at the process of its initialization, adding to the garbage buffer and garbage collection.
Official documentation Please bash Garbage Collection
Chinese version address: http://docs.php.net/manual/zh/features.gc.php
"Initialize"
The ZEND/ZEND_GC.C 121 line has a function gc_init that implements the initialization of the GC, with the following code:
Zend_api void Gc_init (tsrmls_d) {if (Gc_g (buf) = = NULL && gc_g (gc_enabled)) {gc_g (BUF) = (gc_root_buffer*) malloc ( sizeof (gc_root_buffer) * gc_root_buffer_max_entries); Gc_g (last_unused) = &gc_g (BUF) [Gc_root_buffer_max_entries];gc_reset (Tsrmls_c);}}
The 123th row determines whether the GC is empty and if it is turned on, and if it is true, go to 124 rows
The 124th line is to call malloc directly to allocate 10,000 gc_root_buffer of memory.
The 125th row sets the global variable last_unused to the end of the GC buffer.
Line 126th resets the entire garbage collection mechanism, starting with the code ZEND/ZEND_GC.C 88 lines, as follows:
Zend_api void Gc_reset (tsrmls_d) {gc_g (gc_runs) = 0; Gc_g (collected) = 0; #if gc_benchgc_g (root_buf_length) = 0; Gc_g (Root_buf_peak) = 0; Gc_g (Zval_possible_root) = 0; Gc_g (Zobj_possible_root) = 0; Gc_g (zval_buffered) = 0; Gc_g (zobj_buffered) = 0; Gc_g (Zval_remove_from_buffer) = 0; Gc_g (Zobj_remove_from_buffer) = 0; Gc_g (Zval_marked_grey) = 0; Gc_g (Zobj_marked_grey) = 0; #endif gc_g (Roots). Next = &gc_g (roots); Gc_g (Roots). Prev = &gc_g (roots); if (Gc_g (BUF)) {gc_g (unused) = NULL; Gc_g (first_unused) = Gc_g (BUF); Gc_g (zval_to_free) = NULL;} else {gc_g (unused) = NULL; Gc_g (first_unused) = NULL; Gc_g (last_unused) = NULL;}}
Line 90th to 91st sets the number of GC runs (gc_runs) and the number of garbage in GC (collected) to 0.
Line 106th to 107th sets the last node and the next node of the doubly-linked header node to point to itself.
About Gc_enabled, which is turned on by default, can be configured in php.ini.
In fact, the modern code in ZEND/ZEND.C 93 line as follows:
Std_zend_ini_boolean ("zend.enable_gc", "1", zend_ini_all,onupdategcenabled, gc_enabled, Zend_gc_globals, Gc_globals)
Initialize call in ZEND/ZEND.C 79 row
Static ZEND_INI_MH (onupdategcenabled)/* {{{*/{onupdatebool (entry, New_value, New_value_length, Mh_arg1, MH_ARG2, Mh_ Arg3, stage TSRMLS_CC); if (Gc_g (gc_enabled)) {gc_init (Tsrmls_c);} return SUCCESS;}
"Add to garbage buffer"
Track PHP source ZEND/ZEND_EXECUTE_API.C 424 Lines
[_zval_ptr_dtor], [Gc_zval_check_possible_root ()], [Gc_zval_check_possible_root ()], [gc_zval_possible _root ()]
Where in the Gc_zval_check_possible_root () function, only garbage collection operations are performed on arrays and objects
The code for the Gc_zval_possible_root function is as follows:
Zend_api void Gc_zval_possible_root (Zval *zv tsrmls_dc) {if (Unexpected (gc_g)! = NULL && GC _zval_address (ZV)! = NULL && gc_zval_get_color (zv) = = Gc_black) && (gc_zval_address (Zv ) < Gc_g (BUF) | | Gc_zval_address (ZV) >= gc_g (last_unused))) {/* The given Zval is a garbage, that's going to being deleted by * currently R Unning GC */return;} if (Zv->type = = Is_object) {gc_zobj_check_possible_root (ZV); return;} Gc_bench_inc (Zval_possible_root); if (Gc_zval_get_color (ZV)! = gc_purple) {gc_zval_set_purple (ZV); Gc_zval_address (Zv)) {Gc_root_buffer *newroot = Gc_g (unused), 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)) {gc_zval_set_black (ZV); return;} Zv->refcount__gc++;gc_collect_cycles (tsrmls_c); zv->refcount__gc--;newroot = GC_G (unused); if (!newRoot) { return;} Gc_zval_set_purPLE (ZV); Gc_g (unused) = Newroot->prev;} Newroot->next = Gc_g (roots). Next;newroot->prev = &gc_g (Roots); Gc_g (Roots). Next->prev = Newroot; Gc_g (Roots). Next = Newroot; Gc_zval_set_address (Zv, newroot); Newroot->handle = 0;newroot->u.pz = Zv; Gc_bench_inc (zval_buffered); Gc_bench_inc (root_buf_length); Gc_bench_peak (Root_buf_peak, root_buf_length);}}
Line 132th to 140th checks to see if the Zval node information has been put into the node buffer, and if it has been put into the node buffer, it will be returned directly, which optimizes its performance.
Line 142th to 145th deals with object nodes, returns directly, and does not perform any subsequent operations.
Line 149th Determines whether the node has been marked purple, and if it is purple it is no longer added to the node buffer, where a node is guaranteed to perform only one operation added to the buffer.
The 150th line will be colored purple to indicate that the node has been added to the buffer, and you don't have to add it next time.
Line 153th to 157th finds the location of the new node and, if the buffer is full, performs a garbage collection operation.
The 176th to 184th Row adds a new node to the doubly linked list where the buffer is located.
"Garbage Collection Process"
In the Gc_zval_possible_root function, when the buffer is full, the program calls the Gc_collect_cycles function to perform a garbage collection operation. Starting with the Zend/zend_gc.c file 615 line, the implementation code is as follows:
Zend_api int Gc_collect_cycles (tsrmls_d) {int count = 0; if (gc_g (Roots). Next! = &gc_g (Roots)) {Zval_gc_info *p, *q, * Orig_free_list, *orig_next_to_free; if (Gc_g (gc_active)) {return 0;} Gc_g (gc_runs) + +; Gc_g (zval_to_free) = Free_list_end; Gc_g (gc_active) = 1;gc_mark_roots (Tsrmls_c); Gc_scan_roots (Tsrmls_c); Gc_collect_roots (Tsrmls_c); Orig_free_list = Gc_g (free_list); orig_next_to_free = Gc_g (next_to_free);p = Gc_g (free_list) = Gc_g (Zval_to_free); Gc_g (zval_to_free) = NULL; Gc_g (gc_active) = 0; /* First Call destructors */while (P! = free_list_end) {if (Z_type (p->z) = = Is_object) {if (EG (objects_store). Object_bu Ckets &&eg (Objects_store). Object_buckets[z_obj_handle (p->z)].valid &&eg (objects_store). Object _buckets[z_obj_handle (p->z)].bucket.obj.refcount <= 0 &&eg (objects_store). object_buckets[Z_OBJ_ HANDLE (p->z)].bucket.obj.dtor &&! Eg (objects_store). Object_buckets[z_obj_handle (p->z)].destructor_called) {eg (objects_store). object_buckets[Z_ Obj_HANDLE (p->z)].destructor_called = 1; EG (Objects_store). Object_buckets[z_obj_handle (p->z)].bucket.obj.refcount++; Eg (objects_store). Object_buckets[z_obj_handle (p->z)].bucket.obj.dtor (eg (objects_store). Object_buckets[Z_OBJ _handle (p->z)].bucket.obj.object, Z_obj_handle (p->z) tsrmls_cc); EG (Objects_store). Object_buckets[z_obj_handle (P->z)].bucket.obj.refcount--;} count++;p = P->u.next;} /* Destroy zvals */p = Gc_g (free_list); while (P! = free_list_end) {gc_g (Next_to_free) = P->u.next;if (Z_type (p->z) = = Is_object) {if (EG (objects_store). Object_buckets &&eg (Objects_store). Object_buckets[z_obj_handle (p->z )].valid &&eg (Objects_store). Object_buckets[z_obj_handle (p->z)].bucket.obj.refcount <= 0) {EG ( Objects_store). Object_buckets[z_obj_handle (p->z)].bucket.obj.refcount = 1; Z_type (p->z) = IS_NULL;ZEND_OBJECTS_STORE_DEL_REF_BY_HANDLE_EX (Z_obj_handle (p->z), Z_OBJ_HT (p->z) TSRMLS_ CC);}} else if (z_type (p->z) = = Is_array) {z_type (p->z) = Is_null;zend_hash_destroy (Z_arrval (p->z)); Free_hashtable (Z_arrval (P->z));} else {zval_dtor (&p->z); Z_type (p->z) = Is_null;} p = gc_g (next_to_free);} /* Free Zvals */p = Gc_g (Free_list), while (P! = free_list_end) {q = p->u.next; FREE_ZVAL_EX (&p->z);p = q;} Gc_g (Collected) + = count; Gc_g (free_list) = Orig_free_list; Gc_g (next_to_free) = Orig_next_to_free;} return count;}
Row No. 619 Determines whether the buffer is empty and does not perform a garbage collection operation if it is empty
The No. 622 line determines whether the garbage collection operation is regular, and if it is in progress, returns directly
The No. 625 to No. 627 row will be garbage collection operations plus 1, initialize the idle list, set gc_active to 1 to indicate that garbage regression is in progress
Line No. 628 here for the algorithm in its official document, step B, the algorithm uses a depth-first search to find all possible roots, and after finding the reference count in each variable container minus 1 ″, to ensure that the same variable container is not reduced by two "1″, the gray mark has been reduced by 1.
Line No. 629 This is the algorithm's step C, the algorithm once again uses the depth-first search for each root node, checking the reference count of each variable container. If the reference count is 0, the variable container is marked with white. If the number of references is greater than 0, the operation (that is, the reference count plus 1) is restored at this point using the depth-first search and the reference count minus 1, and then re-marked with black.
In the last step of the No. 630 line of the algorithm, D, the algorithm traverses the root buffer to remove the variable container root (Zval roots) from there, and checks whether there is a variable container that was marked white in the previous step. Each variable container that is marked with white is cleared.
in [Gc_collect_cycles (), Gc_collect_roots (), Zval_collect_white (), we can see that the nodes that are marked with white are added to the global variable Zval_to_ The free list. This list is useful in subsequent operations.
The No. 632 to No. 633 row of global variables free_list and next_to_free are stored in the corresponding temporary variables, and will revert to the state at the end.
Line No. 634 to No. 635 initializes the list that needs to be purged, empties the list of zval that will be emptied, and the state of the garbage collection operation is inactive.
Line No. 639 to No. 655 calls the destructor for the first time and counts the number of cleared variables
Line No. 657 to No. 678 clears the variable
Line No. 682 to No. 686 frees memory
Line No. 687 to No. 689 deals with garbage counts, restores free_list and next_to_free variables
The above is the whole content of this article, I hope that everyone's learning has helped, more relevant content please pay attention to topic.alibabacloud.com!