php5.x的字符串結構:php
struct _zval_struct {
/* Variable information */
struct {
char *val;
int len;
} str;
zend_uint refcount__gc;
zend_uchar type; /* active type */
zend_uchar is_ref__gc;
};
複製代碼
能夠看到php5的字符串是直接以結構體形式放在zval結構體中的。數組
再來看下php7的字符串結構:緩存
struct _zend_string {
zend_refcounted_h gc;
zend_ulong h; /* hash value */
size_t len;
char val[1];
};
複製代碼
php7中是單獨增長了一個zend_string結構體來表示字符串,也就是和zval分離了。安全
柔性數組有什麼好處呢?
在php7中,字符串初始化內存時的函數是zend_string_alloc,具體以下:bash
static zend_always_inline zend_string *zend_string_alloc(size_t len, int persistent)
{
zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
GC_SET_REFCOUNT(ret, 1);
GC_TYPE_INFO(ret) = IS_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << GC_FLAGS_SHIFT);
ZSTR_H(ret) = 0;
ZSTR_LEN(ret) = len;
return ret;
}
複製代碼
能夠看到,在分配內存時,用到了_ZSTR_STRUCT_SIZE(len)
,而後跟蹤進去能夠找到#define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1)
,這個_ZSTR_HEADER_SIZE實際上是#define _ZSTR_HEADER_SIZE XtOffsetOf(zend_string, val)
,其實到這裏就能夠看出,他分配的內存空間實際上是zend_string結構體到柔性數組的長度加上len再加上1,爲何加1呢,由於還有個結束符「\0」。php7
而至此能夠看出,柔性數組val其實佔據告終構體末尾連續的一塊內存,能夠用於存儲不定長度的字符串值。這樣,zend_string的val就和其餘字段一塊兒存儲在了同一塊連續的內存塊中,再分配、釋放內存的時候能夠把struct看成總體來處理。函數
php5中則將字符串值單獨出來用指針表示,存儲在另外一塊內存中,這就表示結構體和字符串值是分散的兩塊內存,在讀取到zval結構體所在內存後,還須要再到零一塊內存中才能讀取字符串的值。ui
php7則只須要一次內存讀取便可,節省了一次內存讀寫:spa