写时复制(Copy-on-Write,也缩写为COW),顾名思义,就是在写入时才真正复制一份内存进行修改。 COW最早应用在*nix系统中对线程与内存使用的优化,后面广泛的被使用在各种编程语言中,如C++的STL等。 在PHP内核中,COW也是主要的内存优化手段。 在前面关于变量和内存的讨论中,引用计数对变量的销毁与回收中起着至关重要的标识作用。 引用计数存在的意义,就是为了使得COW可以正常运作,从而实现对内存的优化使用。

写时复制的作用

以下是一段代码:

<?php

var_dump(memory_get_usage());//先打印出当前内存情况

$arr = array_fill(0, 100000, 'tioncico');//生成一个0-100000键的数组

var_dump(memory_get_usage());//打印内存

$arr_copy = $arr;//把数组赋值给另一个

var_dump(memory_get_usage());//打印内存

$j=1;

foreach($arr_copy as $i) {//循环遍历该数组键值查看内存情况

    $j += count($i);

}

var_dump(memory_get_usage());//打印内存

也就是说,就算我们不使用引用,php变量在传值,赋值的情况,都是指向同一个内存,但是如果当$arr_copy的值改变了会怎么样呢?<?php

var_dump(memory_get_usage());

//$tipi = array_fill(0, 3, 'php-internal');

//不用array_fill的原因可自己试着打印下

$tipi[0]='php-internal';

$tipi[1]='php-internal';

$tipi[2]='php-internal';

 

var_dump(memory_get_usage());

 

$copy = $tipi;

 

xdebug_debug_zval('tipi', 'copy');

 

var_dump(memory_get_usage());

 

$copy[0] = '123';

 

xdebug_debug_zval('tipi', 'copy');

 

var_dump(memory_get_usage());

结果如下:(注意:该结果是php5.6web环境下的,php7的引用不同)

可看出,当$arr把值赋值给$arr_copy时,执行内存是没有明显变化的,并没有直接增加5443320内存量

甚至在之后的foreach遍历中,也是没有增加内存的.

因为当$arr赋值给$arr_copy时,并不是在内存中复制了整个$arr的值,而是将$arr_copy的值指向了$arr,相当于在取$arr_copy的数据时,指向的还是$arr存值的内存

也就是说,就算我们不使用引用,php变量在传值,赋值的情况,都是指向同一个内存,但是如果当$arr_copy的值改变了会怎么样呢?

<?php

var_dump(memory_get_usage());

//$tipi = array_fill(0, 3, 'php-internal');

//不用array_fill的原因可自己试着打印下

$tipi[0]='php-internal';

$tipi[1]='php-internal';

$tipi[2]='php-internal';

var_dump(memory_get_usage());

$copy = $tipi;

xdebug_debug_zval('tipi', 'copy');

var_dump(memory_get_usage());

$copy[0] = '123';

xdebug_debug_zval('tipi', 'copy');

var_dump(memory_get_usage());

结果如下:(注意:该结果是php5.6web环境下的,php7的引用不同)

可以看出,当$copy[0]值改变时,php将会给$copy[0]重新申请内存,然后赋之以新值,但不影响其他值的内存状态。
写时复制的最小粒度,就是zval结构体, 而对于zval结构体组成的集合(如数组和对象等),在需要复制内存时,将复杂对象分解为最小粒度来处理。
这样做就使内存中复杂对象中某一部分做修改时,不必将该对象的所有元素全部“分离”出一份内存拷贝, 从而节省了内存的使用。

(文中的xdebug_debug_zval是xdebug扩展中的函数,用于查看变量的引用信息)

以上就是phpCOW机制详解的详细内容,更多请关注php中文网其它相关文章!

phpCOW机制详解的更多相关文章

  1. 从mixin到new和prototype:Javascript原型机制详解

    从mixin到new和prototype:Javascript原型机制详解   这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...

  2. 浏览器 HTTP 协议缓存机制详解

    最近在准备优化日志请求时遇到了一些令人疑惑的问题,比如为什么响应头里出现了两个 cache control.为什么明明设置了 no cache 却还是发请求,为什么多次访问时有时请求里带了 etag, ...

  3. JVM的垃圾回收机制详解和调优

    JVM的垃圾回收机制详解和调优 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都 ...

  4. ThreadPoolExecutor运转机制详解

    ThreadPoolExecutor运转机制详解 - 走向架构师之路 - 博客频道 - CSDN.NET 最近发现几起对ThreadPoolExecutor的误用,其中包括自己,发现都是因为没有仔细看 ...

  5. Linux 内存机制详解宝典

    Linux 内存机制详解宝典 在linux的内存分配机制中,优先使用物理内存,当物理内存还有空闲时(还够用),不会释放其占用内存,就算占用内存的程序已经被关闭了,该程序所占用的内存用来做缓存使用,对于 ...

  6. PHP的垃圾回收机制详解

    原文:PHP的垃圾回收机制详解 最近由于使用php编写了一个脚本,模拟实现了一个守护进程,因此需要深入理解php中的垃圾回收机制.本文参考了PHP手册. 在理解PHP垃圾回收机制(GC)之前,先了解一 ...

  7. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  8. Android事件分发机制详解

    事件分发机制详解 一.基础知识介绍 1.经常用的事件有:MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE,MotionEvent.ACTION_UP等 2 ...

  9. Android Binder机制详解:手写IPC通信

    想要掌握一样东西,最好的方式就是阅读理解它的源码.想要掌握Android Binder,最好的方式就是写一个AIDL文件,然后查看其生成的代码.本文的思路也是来自于此. 简介 Binder是Andro ...

随机推荐

  1. sklearn中pipeline的用法和FeatureUnion

    一.pipeline的用法 pipeline可以用于把多个estimators级联成一个estimator,这么 做的原因是考虑了数据处理过程中一系列前后相继的固定流程,比如feature selec ...

  2. 【LGP5439】【XR-2】永恒

    题目 是个傻题 显然枚举每一条路径经过了多少次,如果\(u,v\)在树上不是祖先关系的话经过\((u,v)\)这条路径的路径条数就是\(sum_u\times sum_v\) 于是我们子树大小映射到\ ...

  3. python接口自动化(get请求)

    python接口自动化(get请求) get请求的目的:查询资源 一.导包 二.请求的URL 三.请求的参数 四.获取请求的URL 五.获取响应的状态码 六.获取响应的本文信息 #导包 import ...

  4. static/extern&const个人理解

    //const仅仅用来修饰右边的变量(基本数据变量p,指针变量*p) static NSString *const keyA = @"keyA"; static NSString ...

  5. Java怎样实现解析身份证号

    身份证号解析,demo /** * 身份证号解析demo * */ public class TestArea { public static void main(String[] args) { S ...

  6. python中的 += 语法的使用

    python中有个缩略的写法,如下 a = a +1 等同于 a +=1 发现了一个有趣之处,+=的写法中间不能有空格,否则报错,测试如下 Python 3.7.1 (v3.7.1:260ec2c36 ...

  7. python 之单例模式

    单例模式1 单例=>只有一个单例2 静态方法+静态字段3 所有实例中等转的内容相同时 用单例模式class Sqllite: __instance=None def __init__(self) ...

  8. java 选择结构if

    图1-1      if…else if…else语句的流程图 选择结构if语句与三元运算转换 三元运算符,它和if-else语句类似,语法如下: 判断条件 ? 表达式1 : 表达式2 三元运算符会得 ...

  9. Jmeter-BeanShell断言:将数据库结果封装成list作为参数

    import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjso ...

  10. from urllib import parse模块的使用

    一.介绍 定义了url的标准接口,实现url的各种抽取 parse模块的作用:url的解析,合并,编码,解码 二.代码 方法一:urlparse 实现url的识别和分段 from urllib imp ...