深入解析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 5.0对象模型深度探索之绑定
Sep 05 PHP
WINDOWS服务器安装多套PHP的另类解决方案
Oct 09 PHP
PHP 查找字符串常用函数介绍
Jun 07 PHP
Linux中用PHP判断程序运行状态的2个方法
May 04 PHP
PHP中SESSION的注销与清除
Apr 16 PHP
PHP判断来访是搜索引擎蜘蛛还是普通用户的代码小结
Sep 14 PHP
PHP入门教程之PHP操作MySQL的方法分析
Sep 11 PHP
yii框架redis结合php实现秒杀效果(实例代码)
Oct 26 PHP
php删除一个路径下的所有文件夹和文件的方法
Feb 07 PHP
PHP基于面向对象实现的留言本功能实例
Apr 04 PHP
php图片裁剪函数
Oct 31 PHP
laravel框架 api自定义全局异常处理方法
Oct 11 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
PHP基于php_imagick_st-Q8.dll实现JPG合成GIF图片的方法
2014/07/11 PHP
PHP中的日期加减方法示例
2014/08/21 PHP
PHP时间和日期函数详解
2015/05/08 PHP
PHP PDOStatement::errorCode讲解
2019/01/31 PHP
thinkphp5.1框架模板布局与模板继承用法分析
2019/07/19 PHP
laravel框架实现后台登录、退出功能示例
2019/10/31 PHP
Javascript模块模式分析
2008/05/16 Javascript
模拟jQuery ajax服务器端与客户端通信的代码
2011/03/28 Javascript
JQuery调用绑定click事件的3种写法
2015/03/28 Javascript
js改变style样式和css样式的简单实例
2016/06/28 Javascript
js随机生成一个验证码
2017/06/01 Javascript
vue中各组件之间传递数据的方法示例
2017/07/27 Javascript
jQuery实现所有验证通过方可提交的表单验证
2017/11/21 jQuery
详解Angular5 路由传参的3种方法
2018/04/28 Javascript
vue v-on:click传递动态参数的步骤
2020/09/11 Javascript
[02:22:36]《加油!DOTA》总决赛
2014/09/19 DOTA
[00:29]2019完美世界全国高校联赛(秋季赛)总决赛海口落幕
2019/12/10 DOTA
Python编写的com组件发生R6034错误的原因与解决办法
2013/04/01 Python
一个计算身份证号码校验位的Python小程序
2014/08/15 Python
Python实现SVN的目录周期性备份实例
2015/07/17 Python
python 读取修改pcap包的例子
2019/07/23 Python
深入学习python多线程与GIL
2019/08/26 Python
使用pth文件添加Python环境变量方式
2020/05/26 Python
英国舒适型鞋履品牌:FitFlop
2017/05/17 全球购物
李维斯法国官网:Levi’s法国
2019/07/13 全球购物
对象的序列化(serialization)类是面向流的,应如何将对象写入到随机存取文件中
2015/06/22 面试题
房地产销售计划书
2014/01/10 职场文书
路政管理求职信
2014/06/18 职场文书
简单通用的简历自我评价
2014/09/21 职场文书
高考学习决心书
2015/02/04 职场文书
2015年大学班长个人工作总结
2015/04/24 职场文书
2015年感恩母亲节活动方案
2015/05/04 职场文书
安全生产培训心得体会
2016/01/18 职场文书
创业计划书之烤红薯
2019/09/26 职场文书
Redis全局ID生成器的实现
2022/06/05 Redis
Python使用Beautiful Soup(BS4)库解析HTML和XML
2022/06/05 Python