php变量之写时复制机制(copy on write)

     编程思想虽然可以共用,不过语言间的差异还是比较明显的,只是使用者之间没有意识到而己,而了解其中的差异对于编写程序以及把握性能还是有好处的。下面我们来介绍下PHP的一个很重要的机制copy on write,我们先以最简单的变量来介绍这个机制,在说这个之前,笔者先来介绍下弱类型是怎么实现的。

 

     大家都知道,PHP是由C实现的,可是C是强类型语言,PHP怎么做到弱类型语言。一起来看下,PHP变量在C语言底层中的代码,

    

typedef struct _zval_struct zval;
typedef unsigned int zend_uint;
typedef unsigned char zend_uchar;

struct _zval_struct {
    zvalue_value value;      /*注意这里,这个里面存的才是变量的值*/
    zend_uint refcount__gc;  /*引用计数*/
    zend_uchar type;        /* 变量当前的数据类型 */
    zend_uchar is_ref__gc;   /*变量是否引用*/
};



typedef union _zvalue_value {
    long lval;      /*PHP中整型的值*/
    double dval;    /*PHP的浮点数值*/
    struct {      
        char *val;
        int len;
    } str;               /*PHP的字符串*/
    HashTable *ht;     /*数组*/
    zend_object_value obj;  /*对象*/
} zvalue_value;

  本人加了点注释,大家可以发现,实际上我们在PHP用的变量,低层是一个结构体zval,里面的zvalue_value结构体实际上是个联合体,这个联合体才是实际存放着PHP的变量值,下面我们以实际的PHP代码例子来表示整个工作过程,注意上面的引用计数。先来看C语言的,首先是非函数部分,函数部分下一章节来讲

       

int i = 4;  //alloca方式在内存中分配空间,这个变量在内存中的栈区
int j = i;   //alloca方式在内存中分配空间,并且将原先内存空间里面的数据复制到新的内存空间中,这个变量在内存的栈区
int j = 5;  //不分配内存空间,对变量j所在的栈区空间的数据进行修改

 

来看PHP部分的

$i = 4;   //内核创建一个zval指针,并且为其以堆的方式开辟空间,让指针指向这个空间,将zval中的成员引用计数置为1,类型标记为整形,并且申请一个zvalue_value指针,同样以堆的方式以其开辟空间,同时将该联合体中的lval赋值为4,并且在symbal_table的hash表中记录变量i和zval指针的映射关系
$j = $i;   //没有在申请内存空间,在zval的成员中引用计数标记为2
$j = 5;   //内核重新创建zval指针,重复下上面的步骤,我就不重复说明了,重点是将旧的zval引用计数标记为1

 

    从这个地方发现几个重要点

1.所有的php变量开辟的内存空间都是在堆中,无论是临时变量还是全局变量,只是php的临时变量记录在active_symbal_table表中,全局变量记录中symbal_table表中

2.php干嘛比C慢。多做了这么多事,能不慢吗?

3.当php类似$j = $i这种变量赋值时,是没有内存开销的,也就是你赋值个几万个,也只是引用计数变成几万而己,这个和C语言是不一样的。而当变量的值发生变化时,才会进行重新开辟内存空间,这个机制我们称为写时复制机制

 

额外细节部分,当php内核发现,int的数值溢出时,也就是超出整型的范围时,自动转换为float,有兴趣的读者可以自己写个很大的整型,但是不能超出float取值范围,看看var_dump数据类型是什么。

 

最后部分:

php对象部分因为默认是引用方式的,所以就是赋值完,再改变对象的成员变量,也不会启用写时复制的,如以下

class Test {
     public $var = 999;
}

$test1 = new Test();
$test2 = $test1;  //只是引用计数加1而己,没有开辟新的内存空间
$test2->var = 1000;


echo $test1->var;  //此时的值也为1000

$test3 = clone $test1;  //这个才是正在重新开辟新的内存空间

 

posted @ 2015-08-08 00:49  LYC的博客  阅读(2462)  评论(0编辑  收藏  举报