這篇文章主要介紹了關於淺談PHP原始碼三十三:PHP5.3新增加的垃圾回收機制(Garbage Collection)基礎,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
淺談PHP源碼三十三:PHP5.3新增加的垃圾回收機制(Garbage Collection)基礎
PHP5.3中新增加了垃圾回收機制,據說很先進,據說引誘了我去看看其先進的實現。
官方說明文件請猛擊Garbage Collection
中文版位址:http://docs.php.net/manual/zh/features.gc.php
【垃圾回收機制的嵌入方式】
zend_gc.h檔案在zend.h的749行被引用:#include “zend_gc.h”
從而替換覆蓋了在237行引用的zend_alloc.h檔案中的ALLOC_ZVAL等宏
zend/zend_gc. h檔案的202行開始
/* The following macroses override macroses from zend_alloc.h */#undef ALLOC_ZVAL#define ALLOC_ZVAL(z) \ do {\ (z) = (zval*)emalloc(sizeof(zval_gc_info));\ GC_ZVAL_INIT(z);\ } while (0)
ALLOC_ZVAL宏在zend_alloc.h中的定義是分配一個zval結構的記憶體空間。新的ALLOC_ZVAL宏分配了一個zval_gc_info結構的巨集。 zval_gc_info的結構如下:
zend/zend_gc.h檔案的91行開始:
typedef struct _zval_gc_info { zval z; union { gc_root_buffer *buffered; struct _zval_gc_info *next; } u;} zval_gc_info;
zval_gc_info的第一個成員為zval結構,這就確保其和以zval變數分配的記憶體的開始對齊,從而在zval_gc_info類型指標的強制轉換時,其可以作為zval使用。關於gc_root_buffer等將在後面的結構和實作時介紹,它定義的PHP垃圾回收機制的快取結構。 GC_ZVAL_INIT用來初始化替代了zval的zval_gc_info,它會把zval_gc_info中的成員u的buffered欄位設為NULL,此欄位僅在將其放入垃圾回收緩衝區時才會有值,否則會一直是NULL。
由於PHP中所有的變數都是以zval變數的形式存在,這裡以zval_gc_info取代zval,從而成功實現垃圾收集機制在原有系統中的整合。
這個有點物件導向中多態的感覺。
【垃圾回收機制的儲存方式】
結點結構:
typedef struct _gc_root_buffer { struct _gc_root_buffer *prev;/* double-linked list */ struct _gc_root_buffer *next; zend_object_handle handle;/* must be 0 for zval */ union { zval *pz; zend_object_handlers *handlers; } u;} gc_root_buffer;
很明顯(見註釋,雖然PHP中的註釋很少,但是有些純粹是糾結的註釋) ,這是一個雙向鍊錶。
在聯合體中的pz變數很明顯就是先前定義的多態的zval_gc_info結構,於是其在鍊錶中的目前結點指標可以透過((zval_gc_info*)(pz))->u .buffered獲取,不過在看其源碼中有多處使用到這個調用方式,為何不另起一個宏呢?難道是怕宏太多,不是啊,PHP就是以宏多著稱,比這個宏嵌套多的宏海了去了。不懂。另外handle等結構是特別針對物件變數的。
緩衝區是話在全域變數中的,和其它模組的全域變數一樣,gc也有自己的全域變數存取巨集GC_G(v),同樣對於全域變數存取巨集在是否ZTS下有不同的實現。
在zend_gc.h中定義的全域變數如下:
typedef struct _zend_gc_globals { zend_bool gc_enabled;/* 是否开启垃圾收集机制 */ zend_bool gc_active;/* 是否正在进行 */ gc_root_buffer *buf;/* 预分配的缓冲区数组,默认为10000(preallocated arrays of buffers) */ gc_root_buffer roots;/* 列表的根结点(list of possible roots of cycles) */ gc_root_buffer *unused;/* 没有使用过的缓冲区列表(list of unused buffers) */ gc_root_buffer *first_unused;/* 指向第一个没有使用过的缓冲区结点(pointer to first unused buffer) */ gc_root_buffer *last_unused;/* 指向最后一个没有使用过的缓冲区结点,此处为标记结束用(pointer to last unused buffer) */ zval_gc_info *zval_to_free;/* 将要释放的zval变量的临时列表(temporaryt list of zvals to free) */ zval_gc_info *free_list;/* 临时变量,需要释放的列表开头 */ zval_gc_info *next_to_free;/* 临时变量,下一个将要释放的变量位置*/ zend_uint gc_runs;/* gc运行的次数统计 */ zend_uint collected; /* gc中垃圾的个数 */ // 省略...
【垃圾回收機制中的顏色標記】
#define GC_COLOR 0x03 #define GC_BLACK 0x00#define GC_WHITE 0x01#define GC_GREY 0x02#define GC_PURPLE 0x03 #define GC_ADDRESS(v) \ ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR))#define GC_SET_ADDRESS(v, a) \ (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & GC_COLOR) | ((zend_uintptr_t)(a))))#define GC_GET_COLOR(v) \ (((zend_uintptr_t)(v)) & GC_COLOR)#define GC_SET_COLOR(v, c) \ (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & ~GC_COLOR) | (c)))#define GC_SET_BLACK(v) \ (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR))#define GC_SET_PURPLE(v) \ (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) | GC_PURPLE))
在PHP的記憶體管理中我們也看到類似的以最後位作為某種類型的標記方式。
這裡以記憶體分配的最後兩位作為整個結構的顏色標記。其中
白色表示垃圾
紫色表示已放入緩衝區
灰色表示已經進行了一次refcount的減一操作
黑色是預設顏色,正常
【zval定義的改變】
PHP3.0版本在zend/zend.h檔中,其定義如下:
struct _zval_struct { /* Variable information */ zvalue_value value;/* value */ zend_uint refcount__gc; zend_uchar type;/* active type */ zend_uchar is_ref__gc;};
在php3.0之前的版本,如php5.2.9版本,在zend/zend.h檔中,其定義如下:
struct _zval_struct { /* Variable information */ zvalue_value value;/* value */ zend_uint refcount; zend_uchar type;/* active type */ zend_uchar is_ref;};
以上就是本文的全部內容,希望對大家的學習有所幫助,更多相關內容請關注PHP中文網!
相關推薦:
淺聊PHP原始碼三十二:PHP記憶體池中的emalloc/efree層與堆(heap)層
淺談PHP源碼三十一:PHP記憶體池中的堆(heap)層基礎
以上是淺談PHP原始碼三十三:PHP5.3新增加的垃圾回收機制(Garbage Collection)基礎的詳細內容。更多資訊請關注PHP中文網其他相關文章!