深入解析PHP的引用计数机制


Posted in PHP onJune 14, 2013

PHP的变量声明并赋值后,变量名存在符号表中,而值和类信息存在zval中,zval中包含四个变量,is_ref,refcount,value,type,zval源码如下

struct _zval_struct {  
    /* Variable information */  
    zvalue_value value;     /* value */  
    zend_uint refcount__gc;  
    zend_uchar type;    /* active type */  
    zend_uchar is_ref__gc;  
};

refcount表示value地址与其相同的zval共有多少个,refcount=0时,zval被销毁
is_ref表示一个zval是否被引用,有“0”和“1”两种状态

此处分析一下什么时候zval会被复制或者开辟新的内存空间呢
1.当is_ref=0,且refcount>1时,如果改变某个指向该zval的变量的值,会生成新zval,原zval的refcount--,例如:$a=1;$b=$a;$b=2;,zval将被复制,也就是说原先ab指向同一个zval,后来b会使用新开辟的zval

2.当is_ref=0,且refcount>1时,如果将zval赋值给某个引用变量,那么用来赋值和变量和被赋值的变量会使用同一个原zval,而其他指向原zval的变量将会指向一个新复制的zval,且refcount会被重新计算,例如:$a=1;$b=$a;$c=$a;$d=&$a;,此时ad使用原zval,bc使用新复制出来的zval

3.当is_ref=1,且refcount>1时,如果将zval复制给某个非引用变量,该非引用变量会使用一个新复制的zval,元zval的refcount不变,例如:$a=1;$b=&$a;$c=$a,那么ab使用原zval,而c使用新复制的zval
type表示该zval的值类型,宏定义如下

#define IS_NULL     0  
#define IS_LONG     1  
#define IS_DOUBLE   2  
#define IS_BOOL     3  
#define IS_ARRAY    4  
#define IS_OBJECT   5  
#define IS_STRING   6  
#define IS_RESOURCE 7  
#define IS_CONSTANT 8  
#define IS_CONSTANT_ARRAY   9

value表示该zval的值,他也是个共同体,代码如下
typedef union _zvalue_value {  
    long lval;                  /* long value */  
    double dval;                /* double value */  
    struct {  
        char *val;  
        int len;  
    } str;  
    HashTable *ht;              /* hash table value */  
    zend_object_value obj;  
} zvalue_value;

现在你知道php是如何类型变换的了,因为他的值存的其实是个可以代表任何类型的结构体,而具体的取值则根据type来决定是用共同体里的哪个变量来存值的

见下面的例子1

.-----------
$a = 1;
$b = $a;
$c = $a;
.-----------
$d = &$a;
.-----------
$a = 2;
.-----------
$b = null;

查看refcount,is_ref,zval的变化
执行完第一部分后来看看输出
1-----------------------------
a:(refcount=3, is_ref=0),int 1
b:(refcount=3, is_ref=0),int 1
c:(refcount=3, is_ref=0),int 1
可以看出来a,b,c使用同一个zval
再看执行完第二部分的
2----------------------------
a:(refcount=2, is_ref=1),int 1
b:(refcount=2, is_ref=0),int 1
c:(refcount=2, is_ref=0),int 1
d:(refcount=2, is_ref=1),int 1
注意此时a,d在一起了,他们使用同一个zval,而bc使用一个新生成的zval,同时重新计算两个zval的refcount和is_ref
3----------------------------
a:(refcount=2, is_ref=1),int 2
b:(refcount=2, is_ref=0),int 1
c:(refcount=2, is_ref=0),int 1
d:(refcount=2, is_ref=1),int 2
可以知道ad这两个is_ref=1的好基友的值是同时改变的
4----------------------------
a:(refcount=2, is_ref=1),int 2
b:(refcount=1, is_ref=0),null
c:(refcount=1, is_ref=0),int 1
d:(refcount=2, is_ref=1),int 2
bc由于他们的zval的is_ref=0,所以他们不是好基友,他们的值不会同时改变,于是bc的zval再次分裂,b = null c = 1
PHP 相关文章推荐
php中的时间处理
Oct 09 PHP
一个PHP缓存类代码(附详细说明)
Jun 09 PHP
去除php注释和去除空格函数分享
Mar 13 PHP
php中curl使用指南
Feb 05 PHP
PHP+Ajax实时自动检测是否联网的方法
Jul 01 PHP
总结对比php中的多种序列化
Aug 28 PHP
Yii框架引入coreseek分页功能示例
Feb 08 PHP
Linux下安装Memcached服务器和客户端与PHP使用示例
Apr 15 PHP
PHP命名空间与自动加载机制的基础介绍
Aug 25 PHP
gearman中任务的优先级和返回状态实例分析
Feb 27 PHP
PHP执行linux命令6个函数代码实例
Nov 24 PHP
php中get_object_vars()在数组的实例用法
Feb 22 PHP
深入解析PHP垃圾回收机制对内存泄露的处理
Jun 14 #PHP
Mysql的Root密码忘记,查看或修改的解决方法(图文介绍)
Jun 14 #PHP
解析php中两种缩放图片的函数,为图片添加水印
Jun 14 #PHP
PHP操作Memcache实例介绍
Jun 14 #PHP
解析PHP处理换行符的问题 \r\n
Jun 13 #PHP
基于PHP5魔术常量与魔术方法的详解
Jun 13 #PHP
基于PHPExcel的常用方法总结
Jun 13 #PHP
You might like
zend framework重定向方法小结
2016/05/28 PHP
php版微信公众平台接口参数调试实现判断用户行为的方法
2016/09/23 PHP
php操作mongodb封装类与用法实例
2018/09/01 PHP
thinkphp5.1框架中容器(Container)和门面(Facade)的实现方法分析
2019/08/05 PHP
农历与西历对照
2006/09/06 Javascript
prototype Element学习笔记(篇二)
2008/10/26 Javascript
JavaScript对象、属性、事件手册集合方便查询
2010/07/04 Javascript
网页打开自动最大化的js代码
2012/08/22 Javascript
jQuery控制输入框只能输入数值的小例子
2013/03/20 Javascript
JS中 用户登录系统的解决办法
2013/04/15 Javascript
JS获取文本框,下拉框,单选框的值的简单实例
2014/02/26 Javascript
JavaScript类继承及实例化的方法
2015/07/25 Javascript
JavaScript文档碎片操作实例分析
2015/12/12 Javascript
Angular 2应用的8个主要构造块有哪些
2016/10/17 Javascript
微信小程序 简单教程实例详解
2017/01/13 Javascript
创建一般js对象的几种方式
2017/01/19 Javascript
JavaScript之Canvas_动力节点Java学院整理
2017/07/04 Javascript
移动web开发之touch事件实例详解
2018/01/17 Javascript
深入剖析Express cookie-parser中间件实现示例
2018/02/01 Javascript
JQuery Ajax动态加载Table数据的实例讲解
2018/08/09 jQuery
通过javascript实现段落的收缩与展开
2019/06/26 Javascript
Python多线程编程(三):threading.Thread类的重要函数和方法
2015/04/05 Python
python3.0 模拟用户登录,三次错误锁定的实例
2017/11/02 Python
python Tkinter版学生管理系统
2019/02/20 Python
分析运行中的 Python 进程详细解析
2019/06/22 Python
python开头的coding设置方法
2019/08/08 Python
python 用户交互输入input的4种用法详解
2019/09/24 Python
python使用HTMLTestRunner导出饼图分析报告的方法
2019/12/30 Python
keras多显卡训练方式
2020/06/10 Python
澳大利亚最大的护发和护肤品购物网站:RY
2019/12/26 全球购物
运动会邀请函范文
2014/02/06 职场文书
舞蹈专业求职信
2014/06/13 职场文书
自查自纠整改报告
2014/11/06 职场文书
2014年依法行政工作总结
2014/11/19 职场文书
小学副班长竞选稿
2015/11/21 职场文书
jdbc使用PreparedStatement批量插入数据的方法
2021/04/27 MySQL