struct _zval_struct {
union {
long lval;
double dval;
struct {
char *val;
int len;
} str;
HashTable *ht;
zend_object_value obj;
zend_ast *ast;
} value;
zend_uint refcount__gc;
zend_uchar type;
zend_uchar is_ref__gc;
};
struct _zval_struct {
union {
zend_long lval; /* long value */
double dval; /* double value */
zend_refcounted *counted;
zend_string *str;
zend_array *arr;
zend_object *obj;
zend_resource *res;
zend_reference *ref;
zend_ast_ref *ast;
zval *zv;
void *ptr;
zend_class_entry *ce;
zend_function *func;
struct {
uint32_t w1;
uint32_t w2;
} ww;
} value;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type, /* active type */
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved) /* call info for EX(This) */
} v;
uint32_t type_info;
} u1;
union {
uint32_t var_flags;
uint32_t next; /* hash collision chain */
uint32_t cache_slot; /* literal cache slot */
uint32_t lineno; /* line number (for ast nodes) */
uint32_t num_args; /* arguments number for EX(This) */
uint32_t fe_pos; /* foreach position */
uint32_t fe_iter_idx; /* foreach iterator index */
} u2;
};
GC
機制:僅支持數組和對象(IS_TYPE_COLLECTABLE
)
- 第一步將紫色標記爲灰色,並將計數引用減
1
- 第二步僅操作灰色。若計數引用大於
0
,則說明非垃圾,標爲黑色,並將計數引用加1
(第一步中做了減1
操作)。若計數引用等於0
,則說明是垃圾,標爲白色。
- 移除黑色(非垃圾,不需要處理),保留白色(垃圾,需要回收)。將白色的計數引用加
1
,然後將處理後的roots
鏈表移動到待釋放列表(to_free
)
- 釋放
to_free
- 計數引用說白了就是用來標記一個變量所指向的值被使用了多少次
- 簡單類型的變量(
true
/false
/double
/long
/null
)不需要引用計數
- 臨時字符串會用到引用計數。但如果變量是字符常量,則不會用到
- 對象、資源和引用在賦值時一定會用到引用計數
- 普通數組在賦值時也會用到引用計數,但是變量是
IS_ARRAY_IMMUTABLE
時,賦值不使用引用計數
- 一個
zval
是否支持引用計數是通過zval.u1.type_flag
來標識的。當type_flag
的第三位被標記爲1
(IS_TYPE_REFCOUNTED
標識),則代表可以引用計數。
- 寫時複製這種機制是用於節省資源的。當變量只是複製後用來展示而不做改變,那麼新老變量指向的都是同一個值。當新老變量有任何一方作出變動,都會觸發寫時複製的機制,使得兩者脫離,分別指向自己私有的值了(這時候不再共用)。
- 對於複製的支持(
IS_TYPE_COPYABLE
)
- 需要查找
IS_TYPE_COPYABLE
,除了對象和資源,其他都支持。意味着對象和資源在賦值操作之後,新的變量和老的變量指向的是同一個對象(資源)。而其他的變量類型則支持賦值(整型和浮點型會直接生成一份新的,不需要計數引用和寫時複製)。
- 只有
string
和array
支持複製
- 對於引用計數的支持(
IS_TYPE_REFCOUNTED
)
- 支持技術引用的類型有:
string
,array
,object
,resource
,refrence