深入解析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数组索引的Key加引号和不加引号的区别
Aug 19 PHP
ThinkPHP调试模式与日志记录概述
Aug 22 PHP
php常用字符串处理函数实例分析
Nov 22 PHP
PHP 双链表(SplDoublyLinkedList)简介和使用实例
May 12 PHP
php写入、删除与复制文件的方法
Jun 20 PHP
微信公众号开发之语音消息识别php代码
Aug 08 PHP
修改Laravel5.3中的路由文件与路径
Aug 10 PHP
基于thinkPHP框架实现留言板的方法
Oct 17 PHP
PHP Header失效的原因分析及解决方法
Nov 16 PHP
php cookie用户登录的详解及实例代码
Jan 03 PHP
PHP十六进制颜色随机生成器功能示例
Jul 24 PHP
Mac M1安装mnmp (Mac+Nginx+MySQL+PHP) 开发环境
Mar 29 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
如何去掉文章里的 html 语法
2006/10/09 PHP
PHP中利用substr_replace将指定两位置之间的字符替换为*号
2011/01/27 PHP
PHP递归遍历指定文件夹内的文件实现方法
2016/11/15 PHP
thinkphp关于简单的权限判定方法
2017/04/03 PHP
jquery提升性能最佳实践小结
2010/12/06 Javascript
table insertRow、deleteRow定义和用法总结
2014/05/14 Javascript
alert和confirm功能介绍
2014/05/21 Javascript
JQuery遍历json数组的3种方法
2014/11/08 Javascript
jQuery对象和DOM对象之间相互转换的方法介绍
2015/02/28 Javascript
jquery实现页面虚拟键盘特效
2015/08/08 Javascript
JS+HTML5实现上传图片预览效果完整实例【测试可用】
2017/04/20 Javascript
Vue.js中轻松解决v-for执行出错的三个方案
2017/06/09 Javascript
JS实现评价的星星功能
2017/08/20 Javascript
轻松理解vue的双向数据绑定问题
2017/10/30 Javascript
Vue2.0 http请求以及loading展示实例
2018/03/06 Javascript
Vue.js子组件向父组件通信的方法实例代码详解
2018/12/10 Javascript
vue点击页面空白处实现保存功能
2019/11/06 Javascript
[00:48]DOTA2国际邀请赛公开赛报名开始 扫码开启逐梦之旅
2018/06/06 DOTA
Python中使用md5sum检查目录中相同文件代码分享
2015/02/02 Python
python爬虫框架scrapy实现模拟登录操作示例
2018/08/02 Python
python如何实现数据的线性拟合
2019/07/19 Python
pytorch:torch.mm()和torch.matmul()的使用
2019/12/27 Python
python函数enumerate,operator和Counter使用技巧实例小结
2020/02/22 Python
linux 下selenium chrome使用详解
2020/04/02 Python
基于Keras的格式化输出Loss实现方式
2020/06/17 Python
提高python代码运行效率的一些建议
2020/09/29 Python
详解Pymongo常用查询方法总结
2021/01/29 Python
CSS3实现的炫酷菜单代码分享
2015/03/12 HTML / CSS
PHP如何自定义函数
2016/09/16 面试题
解释一下ArrayList Vector和LinkedList的实现和区别
2013/04/26 面试题
财务会计专业求职信范文
2013/12/31 职场文书
支部书记四风问题自我剖析材料
2014/09/29 职场文书
2014年家长学校工作总结
2014/11/20 职场文书
2014流动人口计划生育工作总结
2014/12/20 职场文书
先进基层党组织材料
2014/12/25 职场文书
详解如何在Canvas中添加事件的方法
2021/04/17 Javascript