1. 程式人生 > >php 變量的分配和銷毀

php 變量的分配和銷毀

字符 效率 就是 long pos end ber 沒有 struct

1 引用計數

引用計數是指在value中增加一個字段refcount記錄指向當前value的數量,變量復制、函數傳參時並不直接硬拷貝一份value數據,而是將refcount++,變量銷毀時將refcount--,等到refcount減為0時表示已經沒有變量引用這個value,將它銷毀即可。

存儲結構如下:

 1 typedef struct _zend_refcounted_h {
 2     uint32_t         refcount;            /* reference counter 32-bit */
 3     union {
 4         struct
{ 5 ZEND_ENDIAN_LOHI_3( 6 zend_uchar type, 7 zend_uchar flags, /* used for strings & objects */ 8 uint16_t gc_info) /* keeps GC root number (or 0) and color */ 9 } v; 10 uint32_t type_info; 11 } u; 12 } zend_refcounted_h;

引用計數的信息位於給具體value結構的gc中,例如在字符串變量中:

1 typedef struct _zend_string     zend_string;
2 struct _zend_string {
3     zend_refcounted_h gc;
4     zend_ulong        h;                /* hash value */
5     size_t            len;
6     char              val[1];
7 };

2 寫時復制

引用計數,多個變量可能指向同一個value,然後通過refcount統計引用數,這時候如果其中一個變量試圖更改value的內容則會重新拷貝一份value修改,同時斷開舊的指向,寫時復制的機制在計算機系統中有非常廣的應用,它只有在必要的時候(寫)才會發生硬拷貝,可以很好的提高效率

不是所有類型都可以copy的,比如對象、資源,實時上只有string、array兩種支持,與引用計數相同,也是通過zval.u1.type_flag標識value是否可復制的

3 變量回收

PHP變量的回收主要有兩種:主動銷毀、自動銷毀。動銷毀指的就是 unset。自動銷毀就是PHP的自動管理機制,在return時減掉局部變量的refcount,即使沒有顯式的return,PHP也會自動給加上這個操作,另外一個就是寫時復制時會斷開原來value的指向,這時候也會檢查斷開後舊value的refcount。

4 垃圾回收

PHP變量的回收是根據refcount實現的,當unset、return時會將變量的引用計數減掉,如果refcount減到0則直接釋放value,這是變量的簡單gc過程

但是實際過程中出現gc無法回收導致內存泄漏的bug,先看下一個例子:

1 $a = [1];
2 $a[] = &$a;
3 unset($a);

可以看到,unset($a)之後由於數組中有子元素指向$a,所以refcount > 0,無法通過簡單的gc機制回收,這種變量就是垃圾,垃圾回收器要處理的就是這種情況,目前垃圾只會出現在array、object兩種類型中,所以只會針對這兩種情況作特殊處理:當銷毀一個變量時,如果發現減掉refcount後仍然大於0,且類型是IS_ARRAY、IS_OBJECT則將此value放入gc可能垃圾雙向鏈表中,等這個鏈表達到一定數量後啟動檢查程序將所有變量檢查一遍,如果確定是垃圾則銷毀釋放。

php 變量的分配和銷毀