Basic knowledge
Byte length of each type (x86-64 system)
int 4 bytes
char 1 byte
long 8 bytes
pointer 8 bytes
byte alignment
struct test{ char a; int b; long c; void *d; int e; char *f; };
If you add the number of bytes of each type separately, it is 33 bytes, but actually 40 bytes are used
The essence of memory alignment is the requirement of cpu for program memory data acquisition, which can speed up the process of data IO and avoid unnecessary calculation.
union
uniontest{ char a; int b; long c; };
The consortium only shares memory and only uses the memory size of the largest member
For example, define a c file as follows
union data { u_int32_t a; u_int32_t b; u_int32_t c; } d; int main() { d.a = 30; printf("a %d b %d c %d\n", d.a, d.b, d.c); d.b = 10; printf("a %d b %d c %d\n", d.a, d.b, d.c); }
The result of compilation and execution is,
$ gcc union.c $ ./a.out a 30 b 30 c 30 a 10 b 10 c 10
With the basic knowledge, let's take a look at the design of zval
zval design of PHP5
In PHP5_ zval_struct (zval) structure
struct _zval_struct{ zvalue_value value; /*value value*/ zend_uint refcount__gc; /*type*/ zend_uchar type; zend_uchar is_ref__gc; }; typedef union_zvalue _value { long lval; /*Long integer*/ double dval; /*float */ struct{ char *val; int len; } str; HashTable *ht;/*HashTable number*/ zend_object_value obj; zend_ast *ast; } zvalue_value;
It is easy to see from the union structure that the integer value of php is actually a long integer, the floating-point number is double, and the string is a structure that represents the byte array and length; The rest is arrays and objects;
The zval structure represents a zvalue_value and reference count, as well as variable type and whether to reference type, etc.
Changes of zval structure after using zend memory pool
typedef struct _zend_mm_block_info { size_t _size; size_t _prev; } zend_mm_block_info; typedef struct _zend_mm_block { zend_mm_block_infoinfo; } zend_mm_block;
Finally, the actual memory size occupied by a variable in PHP5 is 48 bytes
This 48 byte size is actually a lot of waste, and PHP developers have made key optimization in PHP7.
- Digression: PHP5 3 resolve circular references
Expand zval by rewriting the macro assigned to zval
#undef ALLOC_ZVAL #define ALLOC_ZVAL(z)\ do{ \ (z)=(zval*)emalloc(sizeof(zval_gc_info));\ GC_ZVAL_INIT(z); } while(0) typedef struct _zval_gc_info{ zval z; union { gc_root_buffer* buffered; struct _zval_gc_info *next; } u; } zval_gc_info;
From the perspective of the structure, the method of guessing is to judge whether there is a circular reference to the variable through the circular record of the zval structure, which is equivalent to the circular search of the linked list.
Zval design of PHP7
struct _zval_struct { zend_value value; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type,/*Indicate zval type*/ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) } v; uint32_t type_info; } u1; union { uint32_t next; /*Used to resolve hash conflicts. See Chapter 5 for details*/ uint32_t cache_slot; /*Runtime cache*/ uint32_t lineno; /*For zend_ast_zval deposit Line No*/ uint32_t num_args;/*EX(This)Number of parameters*/ uint32_t fe_pos; /*foreach Location of*/ uint32_t fe_iter_idx; /*foreach Mark of cursor*/ uint32_t access_flags; /*Constant access ID of the class*/ uint32_t property_guard; /*Single attribute protection*/ } u2; }; typedef union _zend_value { zend_long lval;/*integer*/ double dval;/*float */ zend_refcounted *counted;/*Reference count*/ zend_string *str;/*String type*/ zend_array *arr;/*Array type*/ zend_object *obj;/*object type*/ zend_resource *res;/*Resource type*/ zend_reference *ref;/*reference type*/ zend_ast_ref *ast;/*Abstract syntax tree*/ zval *zv;/*zval type*/ void *ptr;/*Pointer type*/ zend_class_entry *ce;/*class type*/ zend_function *func;/*function type*/ struct{ uint32_t w1; uint32_t w2; } ww; } zend_value;
There are two more union structures in the main change of zval structure. Let's mainly look at this change.
Meaning of u1 field
- Type: record variable type.
- type_flag: a flag unique to the corresponding variable type. Different types of variables have different flags
/*zval.u1.v.type_flags*/ IS_TYPE_CONSTANT//Is a constant type IS_TYPE_IMMUTABLE//Immutable types, such as arrays in shared memory IS_TYPE_REFCOUNTED//Type of reference count required IS_TYPE_COLLECTABLE//Types that may contain circular references (IS_ARRAY,IS_OBJECT) IS_TYPE_COPYABLE//Types that can be copied
- const_flag: a constant type tag. The corresponding attributes are:
/*zval.u1.v.const_flags*/ #define IS_CONSTANT_UNQUALIFIED 0x010 #define IS_CONSTANT_VISITED_MARK 0x020 #define IS_CONSTANT_CLASS0 x080 /*__CLASS__trail class*/ #define IS_CONSTANT_IN_NAMESPACE 0x100 / * only used in opline > extended_ value*/
- Reserved: reserved fields.
Field information in u2
- Next: used to solve the hash conflict and record the next element position of the conflict
- cache_slot: runtime cache. When the function is executed, it will be searched in the cache first. If it is not in the cache, it will be searched in the global function table.
- lineno: the line number of the file execution, which is applied to the AST node
- num_args: number of parameters passed in during function call
- fe_pos: the current position when traversing the array
- fe_iter_idx: follow me_ The purpose of POS is similar, except that this field is for objects.
- access_flags: the access flag of the object class. Common identifiers include public, protected and private.
- property_guard: prevent circular calls of magic methods in the class,
Memory usage of zval in PHP7
Compared with PHP5's memory occupation of 48 bytes, PHP7's zval memory occupation is much smaller.
reference resources:
https://book.douban.com/subject/30455287/