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

class Test {
     public $var = 999;
}

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

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

$test3 = clone $test1;  //这个才是正在重新开辟新的内存空间
时间: 2024-12-23 21:52:22

php变量之写时复制机制(copy on write)的相关文章

PHP "数组变量"之"写时复制的要点" 只有数组才有的概念。

1.如果数组指针位置非法,复制时,会将新数组指针初始化! 2.值传递时,PHP采用了一个COW(写时复制,copy on write)的优化措施! 写时复制的两个要点: <?php $arr1 = array('吕布','赵云','典韦'); end($arr1);next($arr1); //非法了 $arr2 = $arr1; //复制数组////var_dump($arr2);echo '<br>';var_dump(current($arr2));//初始化$arr2      

Ring3下绕过Windows写时复制机制实现全局EAT钩子

在注入到某进程中对Ntdll下EAT钩子的时候作用域仅仅只是当前进程,可是明明所有进程的Ntdll模块全是映射的同一个啊.原来Windows支持一种机制,允许两个或两个以上的进程共享同一块存储器.不过操作系统会给共享的存储页指定写时复制属性,当有个进程想修改一个共享页面时,操作系统会从内存中找到一个闲置页面并将修改的页面内容复制到这个闲置页面上,再将虚拟地址空间和这个新的页面映射上.那么只需在下钩前先想办法消掉页面的写时复制属性,再hook ntdll的时候就能在Ring3下实现类似Ring0钩

php变量的引用计数器和写时复制

众所周知,PHP是不支持指针的,但是如果希望两个变量同时指向同一内存块怎么办呢?为了解决这个问题,PHP内核里使用了引用计数器. 上篇博文介绍了PHP变量在内核中的存储方式了,zval结构中下面两个成员变量用于引用计数器: is_ref BOOL值,标识变量是否是引用集合. refcount 计算指向引用集合的变量个数. 看下面的php代码 <?php $a = "this is a"; ?> 一个zval结构的实体称为zval容器.在php语言层创建一个变量就会相应地在p

再谈QVector与QByteArray——Qt的写时复制(copy on write)技术

Qt作为一个优秀的跨平台开源C++框架,如果我们只停留在使用它的基础上而不深挖其实现手法,实在是浪费这个知识宝库了~我们在之前的博文QVector的内存分配策略与再谈QVector与std::vector--使用装饰者让std::vector支持连续赋值中简单聊了聊QVector内存分配和赋值方面的一点东西,今天接着从QVector展开谈谈Qt的写时复制技术.老实说,"隐式共享,引用计数,写时复制"也是老调重弹的话题了,不过也是QTL与STL最大的区别之一,这篇博文不详谈"写

php引用和写时复制

在php变量中已经发现 zval结构体中有refcount__gc(引用个数) 和 is_ref__gc(是否被引用) 例如: <?php $a="hello world"; ?> 此时PHP会创建一个zval容器 因为这个变量不是一个引用 所以这个容器的is_ref__gc为false 并且refcount__gc为1 再看下面的代码 <?php $a="hello world"; $b=$a; ?> 这里由于$b并不是引用$a 所以这里的

47-引用计数与写时复制

47-引用计数与写时复制 对于PHP这种需要同时处理多个请求的程序来说,申请和释放内存的时候应该慎之又慎,一不小心便会酿成大错.另一方面,除了要安全申请和释放内存外,还应该做到内存的最小化使用,因为它可能要处理每秒钟数以千计的请求,为了提高系统整体的性能,每一次操作都应该只使用最少的内存,对于不必要的相同数据的复制则应该能免则免.我们来看下面这段PHP代码: <?php $a = 'Hello NowaMagic!'; $b = $a; unset($a); ?> 第一条语句执行后,PHP创建

php 垃圾回收机制----写时复制和引用计数

PHP使用引用计数和写时复制来管理内存.写时复制保证了变量间复制值不浪费内存,引用计数保证了当变量不再需要时,将内存释放给操作系统. 要理解PHP内存管理,首先要理解一个概念----符号表. 符号表的概念: 一个变量有两部分组成:变量名和变量值.而符号表就是将变量名映射到内存中变量值所在地址的数组. 写时复制: 当一个变量的值复制到另一个变量时,PHP没有为复制值使用更多的内存.相反,他会跟新符号表来说明这两个变量拥有相同的内存块.所以下面的代码实际上并没有创建新数组: <?php $peopl

PHP写时复制

原文:http://www.huamanshu.com/blog/2014-05-18.html 起源 写时复制英文名字叫“copy-on-write”,简称“cow”,又名“靠” 今天查了下这个"cow",原来起源于*nix内存管理机制,后来广泛应用在其它开发语言上,C++的STL,还有PHP,相信很多人都了解这个写时复制,经常跟别人侃得甚欢. $foo = 'foo'; $bar = $foo; 不会 初写这样的PHP代码时,常会问,这样的话会不会因为复制而占用更多内存,旁边会有人

php底层--4 写时复制

变量的赋值与引用 例如:$a=3; $b=$a; 这个时候是否就产生了2个结构体呢? No,如果是的话,这两个结构体的type,value全都一样,很浪费呀,所以在PHP实现的时候并没有copy一个结构体出来,而是$a,$b共用一个结构体. 在传值赋值时,并没有新生结构体,而是共用的. $a=3; 产生一个结构体 zvalue:3; type:IS_LONG; refcount_gc:1; is_ref_gc:0; $b=$a; 这个时候并没有新产生一个结构体,而是原来的结构体 refcount