深入解析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读取数据库信息的几种方法
May 24 PHP
php数组一对一替换实现代码
Aug 31 PHP
PHP中数组合并的两种方法及区别介绍
Sep 14 PHP
一个漂亮的php验证码类(分享)
Aug 06 PHP
php中jpgraph类库的使用介绍
Aug 08 PHP
PHP创建桌面快捷方式的实例代码
Feb 17 PHP
PHP以mysqli方式连接类完整代码实例
Jul 15 PHP
php获取图片信息的方法详解
Dec 10 PHP
yii2控制器Controller Ajax操作示例
Jul 23 PHP
php简单统计中文个数的方法
Sep 30 PHP
php+ajax简单实现全选删除的方法
Dec 06 PHP
解决Laravel5.5下的toArray问题
Oct 15 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数据库操作类代码(增,删,改,查)
2013/04/08 PHP
thinkPHP3.2简单实现文件上传的方法
2016/05/16 PHP
使用jQuery的ajax功能实现的RSS Reader 代码
2009/09/03 Javascript
你需要知道的10个最佳javascript开发实践小结
2012/04/15 Javascript
PhotoShop给图片自动添加边框及EXIF信息的JS脚本
2015/02/15 Javascript
JS实现兼容性好,带缓冲的动感网页右键菜单效果
2015/09/18 Javascript
javascript实现别踩白块儿小游戏程序
2015/11/22 Javascript
JS中的二叉树遍历详解
2016/03/18 Javascript
纯JS实现轮播图
2017/02/22 Javascript
JS实现的贪吃蛇游戏案例详解
2019/05/01 Javascript
layui实现三级联动效果
2019/07/26 Javascript
[05:37]DOTA2-DPC中国联赛 正赛 Elephant vs iG 选手采访
2021/03/11 DOTA
Python网络爬虫实例讲解
2016/04/28 Python
对Xpath 获取子标签下所有文本的方法详解
2019/01/02 Python
Pycharm之快速定位到某行快捷键的方法
2019/01/20 Python
Python操作Mongodb数据库的方法小结
2019/09/10 Python
nginx+uwsgi+django环境搭建的方法步骤
2019/11/25 Python
python中sklearn的pipeline模块实例详解
2020/05/21 Python
Python 如何展开嵌套的序列
2020/08/01 Python
Python LMDB库的使用示例
2021/02/14 Python
详解HTML5 LocalStorage 本地存储
2016/12/23 HTML / CSS
HTML5实现可缩放时钟代码
2017/08/28 HTML / CSS
美国大码时尚女装购物网站:ELOQUII
2017/12/28 全球购物
Herve Leger官网:标志性绷带连衣裙等
2018/12/26 全球购物
美丽的珠宝配饰:SmallThings
2019/09/04 全球购物
学校后勤人员职责
2013/12/27 职场文书
创业计划书的主要内容有哪些
2014/01/29 职场文书
《中国梦我的梦》大学生演讲稿
2014/08/20 职场文书
大学生职业生涯十年规划书范文
2014/09/17 职场文书
2014年护士个人工作总结
2014/11/11 职场文书
交通事故案件代理词
2015/05/23 职场文书
2016春季幼儿园小班开学寄语
2015/12/03 职场文书
2016七夕情人节广告语
2016/01/28 职场文书
Vue如何实现组件间通信
2021/05/15 Vue.js
详解分布式系统中如何用python实现Paxos
2021/05/18 Python
MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)
2022/04/09 MySQL