PHP中copy on write写时复制机制介绍


Posted in PHP onMay 13, 2014

什么是写时复制(Copy On Write)?

答:在复制一个对象的时候并不是真正的把原先的对象复制到内存的另外一个位置上,而是在新对象的内存映射表中设置一个指针,指向源对象的位置,并把那块内存的Copy-On-Write位设置为1.这样,在对新的对象执行读操作的时候,内存数据不发生任何变动,直接执行读操作;而在对新的对象执行写操作时,将真正的对象复制到新的内存地址中,并修改新对象的内存映射表指向这个新的位置,并在新的内存位置上执行写操作。

这个技术需要跟虚拟内存和分页同时使用,好处就是在执行复制操作时因为不是真正的内存复制,而只是建立了一个指针,因而大大提高效率。但这不是一直成立的,如果在复制新对象之后,大部分对象都还需要继续进行写操作会产生大量的分页错误,得不偿失。所以COW高效的情况只是在复制新对象之后,在一小部分的内存分页上进行写操作。

在PHP 内核中同样使用了写时复制机制来避免在赋值时导致内存增加,比如我们在使用foreach循环体时,可以发现其中的奥秘,示例代码:

$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as $v){
    $count++;
    //$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;

当我们执行此代码时会得到内存占用为:788

$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as $v){
$count++;
$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;

当我们取消 //$v='aaaaaaaaaaaaaa';  的注释,此时内存占用数值为:840,注意内存增长了。

$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as &$v){
$count++;
//$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;

当我们将foreach中的$v 改写为 &$v 时,不管是否注释循环体中对$v的注释,我们都可以得到内存占用为:788

这里就说明了COW机制的介入,当我们在foreach循环中纯粹的只用到对$v 的读操作时,PHP内核会将$v这个变量的内存地址指向到$arr中数组这一索引的内存地址,并没有将数组中的数据复制一份给到变量$v,此时内存占用情况和使用&$v 是一样的。但当我们在循环体内对$v进行写操作时,写时复制机制就被激活了,此时PHP会重新开辟一段内存空间给到$v变量,而将原先$v指向数组的内存地址给断开了,此时内存必然就会增长了。

这里可以得出另外一个结论:当我们在读取大数据的时候,要注意COW机制引入的内存增长影响,同样避免不必要的对变量写,可以提高代码运行性能。

PHP 相关文章推荐
php中的boolean(布尔)类型详解
Oct 28 PHP
PHP随机生成随机个数的字母组合示例
Jan 14 PHP
PHP实现绘制3D扇形统计图及图片缩放实例
Oct 01 PHP
php集成环境xampp中apache无法启动问题解决方案
Nov 18 PHP
PHP中文编码小技巧
Dec 25 PHP
PHP中isset与array_key_exists的区别实例分析
Jun 02 PHP
使用PHP进行微信公众平台开发的示例
Aug 21 PHP
PHP微信红包生成代码分享
Oct 06 PHP
php中strtotime函数性能分析
Nov 20 PHP
PHP面向对象程序设计之命名空间与自动加载类详解
Dec 02 PHP
Laravel 5.4重新登录实现跳转到登录前页面的原理和方法
Jul 13 PHP
yii框架redis结合php实现秒杀效果(实例代码)
Oct 26 PHP
php读取富文本的时p标签会出现红线是怎么回事
May 13 #PHP
php的慢速日志引起的Mysql错误问题分析
May 13 #PHP
PHP实现的MongoDB数据库操作类分享
May 12 #PHP
PHP中date与gmdate的区别及默认时区设置
May 12 #PHP
PHP三元运算的2种写法代码实例
May 12 #PHP
PHP入门之常量简介和系统常量
May 12 #PHP
PHP实现数字补零功能的2个函数介绍
May 12 #PHP
You might like
PHP的new static和new self的区别与使用
2019/11/27 PHP
javascritp实现input输入框相关限制用法
2007/06/29 Javascript
Javascript Function对象扩展之延时执行函数
2010/07/06 Javascript
js实现网页标题栏闪烁提示效果实例分析
2014/11/20 Javascript
Jquery中CSS选择器用法分析
2015/02/10 Javascript
javascript最基本的函数汇总
2015/06/25 Javascript
jquery仅用6行代码实现滑动门效果
2015/09/07 Javascript
Jquery检验手机号是否符合规则并根据手机号检测结果将提交按钮设为不同状态
2015/11/26 Javascript
玩转JavaScript OOP - 类的实现详解
2016/06/08 Javascript
jQuery Easyui Tabs扩展根据自定义属性打开页签
2016/08/15 Javascript
Bootstrap进度条学习使用
2017/02/09 Javascript
轻松理解JavaScript闭包
2017/03/14 Javascript
jQuery的时间datetime控件在AngularJs中的使用实例(分享)
2017/08/17 jQuery
JavaScript实现QQ列表展开收缩扩展功能
2017/10/30 Javascript
Vue-cli配置打包文件本地使用的教程图解
2018/08/02 Javascript
Vue.js 事件修饰符的使用教程
2018/11/01 Javascript
微信小程序Page中data数据操作和函数调用方法
2019/05/08 Javascript
vue发送websocket请求和http post请求的实例代码
2019/07/11 Javascript
Vue使用Clipboard.JS在h5页面中复制内容实例详解
2019/09/03 Javascript
基于ts的动态接口数据配置的详解
2019/12/18 Javascript
Pthon批量处理将pdb文件生成dssp文件
2015/06/21 Python
Python中操作符重载用法分析
2016/04/29 Python
python解析基于xml格式的日志文件
2017/02/25 Python
Python二叉树定义与遍历方法实例分析
2018/05/25 Python
解析python的局部变量和全局变量
2019/08/15 Python
调用其他python脚本文件里面的类和方法过程解析
2019/11/15 Python
Python3 实现爬取网站下所有URL方式
2020/01/16 Python
用python解压分析jar包实例
2020/01/16 Python
python输入一个水仙花数(三位数) 输出百位十位个位实例
2020/05/03 Python
python exit出错原因整理
2020/08/31 Python
Stutterheim瑞典:瑞典高级外套时装品牌
2019/06/24 全球购物
在C语言中实现抽象数据类型什么方法最好
2014/06/26 面试题
机械专业应届生求职信
2013/12/12 职场文书
个人现实表现材料
2014/02/04 职场文书
五星级酒店餐饮部总监的标准岗位职责
2014/02/17 职场文书
生日寿星公答谢词
2015/09/29 职场文书