深入解析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的引用计数机制
Jun 14 PHP
解析PHP中的内存管理,PHP动态分配和释放内存
Jun 28 PHP
使用php显示搜索引擎来的关键词
Feb 13 PHP
Smarty局部缓存的几种方法简介
Jun 17 PHP
基于ThinkPHP实现批量删除
Dec 18 PHP
Yii实现单用户博客系统文章详情页插入评论表单的方法
Dec 28 PHP
关于扩展 Laravel 默认 Session 中间件导致的 Session 写入失效问题分析
Jan 08 PHP
PHP使用Memcache时模拟命名空间及缓存失效问题的解决
Feb 27 PHP
PHP使用strrev翻转中文乱码问题的解决方法
Jan 13 PHP
总结的一些PHP开发中的tips(必看篇)
Mar 24 PHP
PHP和MYSQL实现分页导航思路详解
Apr 11 PHP
PHP与Web页面的交互示例详解一
Aug 04 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
PHPLog php 程序调试追踪工具
2009/09/09 PHP
PHP isset()与empty()的使用区别详解
2010/08/29 PHP
简单分析ucenter 会员同步登录通信原理
2014/08/25 PHP
php编程实现简单的网页版计算器功能示例
2017/04/26 PHP
php从数据库中读取特定的行(实例)
2017/06/02 PHP
2007/12/23更新创意无限,简单实用(javascript log)
2007/12/24 Javascript
JavaScript动态创建div属性和样式示例代码
2013/10/09 Javascript
Jquery中"$(document).ready(function(){ })"函数的使用详解
2013/12/30 Javascript
jQuery绑定事件不执行但alert后可以正常执行
2014/06/03 Javascript
JavaScript实现的使用键盘控制人物走动实例
2014/08/27 Javascript
JS实现超过长度限制后自动跳转下一款文本框的方法
2015/02/23 Javascript
提交按钮的name='submit'引起的js失效问题及原因
2015/02/25 Javascript
JavaScript数据类型判定的总结笔记
2015/07/31 Javascript
jQuery中的Deferred和promise 的区别
2016/04/03 Javascript
Node.js的Web模板引擎ejs的入门使用教程
2016/06/06 Javascript
ES6新特征数字、数组、字符串
2016/10/01 Javascript
EasyUi 打开对话框后控件赋值及赋值后不显示的问题解决办法
2017/01/19 Javascript
jQuery.cookie.js使用方法及相关参数解释
2017/03/06 Javascript
vue.js如何更改默认端口号8080为指定端口的方法
2017/07/14 Javascript
如何开发出更好的JavaScript模块
2017/12/22 Javascript
Vue render函数实战之实现tabs选项卡组件
2019/04/22 Javascript
vue中利用iscroll.js解决pc端滚动问题
2020/02/15 Javascript
jQuery实现查看图片功能
2020/12/01 jQuery
Python数据库小程序源代码
2019/09/15 Python
Python操作qml对象过程详解
2019/09/26 Python
python网络爬虫 CrawlSpider使用详解
2019/09/27 Python
解决matplotlib.pyplot在Jupyter notebook中不显示图像问题
2020/04/22 Python
CentOS 7如何实现定时执行python脚本
2020/06/24 Python
Python实现播放和录制声音的功能
2020/08/12 Python
python给list排序的简单方法
2020/12/10 Python
c语言常见笔试题总结
2016/09/05 面试题
Linux操作面试题
2012/05/16 面试题
毕业生的自我鉴定该怎么写
2013/12/02 职场文书
创建服务型党组织实施方案
2014/02/25 职场文书
业务员自荐信范文
2014/04/20 职场文书
mysql如何查询连续记录
2022/05/11 MySQL