前提:
1.php为弱语言类型,一开始并不严格规定变量的数据类型
2.php变量都是使用同一个结构体zval(变量容器)。
1. struct _zval_struct {2. /* Variable information */3. zvalue_value value; /* 12字节,变量值 */4. zend_uint refcount; /* 4字节,变量引用计数器,初始为1,存储被引用的次数,是回收zval的条件(refount=0) */5. zend_uchar type; /* 1字节,存储变量的数据类型,4种标量(int,float,string,bool),2种复合(array,object),2种特殊(resoure,null)*/6. zend_uchar is_ref; /* 1字节,是否变量被&引用,0表示非引用,1表示引用 */7. };
总结:
- php在修改一个变量之前,会先检查这个变量的refcount是否大于1,如果大于1,则执行分离的过程。
- 分离:分离两个变量存储的zval的位置,让分开的变量不指向同一个空间。
- 改变:有&引用赋值时,要把新开辟的zval 的 is_ref 赋值为1。
- 判定是否分离的条件:如果is_ref =1 或recount == 1,则不分离。
注意:
数组变量和普通变量生成的zval不同,在循环引用时容易导致内存泄漏,如$a[] = &$a,此时这个zval中的refcount=2,当我们unset($a)后,refcount=1,但是$a已经被销毁,却还存在$a[]指向这个zval,这样就占着内存释放不了导致内存泄漏。
PHP5.3之后引入新的垃圾回收机制避免这种情况发生,官方具体文档:http://php.net/manual/zh/features.gc.php
