深入解析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 session 预定义数组
Mar 16 PHP
php生成局部唯一识别码LUID的代码
Oct 06 PHP
php ci框架验证码实例分析
Jun 26 PHP
使用php判断服务器是否支持Gzip压缩功能
Sep 24 PHP
php ZipArchive压缩函数详解实例
Nov 06 PHP
浅谈PHP变量作用域以及地址引用问题
Dec 27 PHP
推荐25款php中非常有用的类库
Sep 29 PHP
推荐十款免费 WordPress 插件
Mar 24 PHP
Zend Framework教程之Application和Bootstrap用法详解
Mar 10 PHP
PHP页面输出时js设置input框的选中值
Sep 30 PHP
PHP多维数组元素操作类的方法
Nov 14 PHP
php语法检查的方法总结
Jan 21 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/10/18 PHP
PHP的压缩函数实现:gzencode、gzdeflate和gzcompress的区别
2016/01/27 PHP
控制打印时页眉角的代码
2007/02/08 Javascript
JavaScript 直接操作本地文件的实现代码
2009/12/01 Javascript
jQuery插件原来如此简单 jQuery插件的机制及实战
2012/02/07 Javascript
动态加载JS文件的三种方法
2013/11/08 Javascript
Jquery插件分享之气泡形提示控件grumble.js
2014/05/20 Javascript
使用Node.js实现HTTP 206内容分片的教程
2015/06/23 Javascript
JavaScript实现图片轮播的方法
2015/07/31 Javascript
微信小程序(应用号)开发新闻客户端实例
2016/10/24 Javascript
关于bootstrap日期转化,bootstrap-editable的简单使用,bootstrap-fileinput的使用详解
2017/05/12 Javascript
详解vue-cli开发环境跨域问题解决方案
2017/06/06 Javascript
vue 监听屏幕高度的实例
2018/09/05 Javascript
javascript对HTML字符转义与反转义
2018/12/13 Javascript
vue 中Virtual Dom被创建的方法
2019/04/15 Javascript
[01:12:27]EG vs Secret 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
Python 爬虫图片简单实现
2017/06/01 Python
Python的mysql数据库的更新如何实现
2017/07/31 Python
使用Python通过win32 COM打开Excel并添加Sheet的方法
2018/05/02 Python
使用Python通过win32 COM实现Word文档的写入与保存方法
2018/05/08 Python
python使用原始套接字发送二层包(链路层帧)的方法
2019/07/22 Python
python英语单词测试小程序代码实例
2019/09/09 Python
PIL包中Image模块的convert()函数的具体使用
2020/02/26 Python
Python用类实现扑克牌发牌的示例代码
2020/06/01 Python
Python中实现一行拆多行和多行并一行的示例代码
2020/09/06 Python
CSS3 linear-gradient线性渐变生成加号和减号的方法
2017/11/21 HTML / CSS
英国百安居装饰建材网上超市:B&Q
2016/09/13 全球购物
简述使用ftp进行文件传输时的两种登录方式?它们的区别是什么?常用的ftp文件传输命令是什么?
2016/11/20 面试题
C#中有没有静态构造函数,如果有是做什么用的?
2016/06/04 面试题
企业内部培训方案
2014/02/04 职场文书
2014年银行工作总结范文
2014/11/12 职场文书
兵马俑导游词
2015/02/02 职场文书
企业法律事务工作总结
2015/08/11 职场文书
学校中层领导培训心得体会
2016/01/11 职场文书
未来,这5大方向都很适合创业
2019/07/22 职场文书
springboot 多数据源配置不生效遇到的坑及解决
2021/11/17 Java/Android