您的位置 首页 php

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

Copy on write,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; //这个才是正在重新开辟新的内存空间
 

文章来源:智云一二三科技

文章标题:php变量之写时复制机制(copy on write)

文章地址:https://www.zhihuclub.com/149417.shtml

关于作者: 智云科技

热门文章

网站地图