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 相关文章推荐
在PHP3中实现SESSION的功能(二)
Oct 09 PHP
php在线打包程序源码
Jul 27 PHP
利用PHP+JS实现搜索自动提示(实例)
Jun 09 PHP
destoon复制新模块的方法
Jun 21 PHP
PHP+FFMPEG实现将视频自动转码成H264标准Mp4文件
Sep 24 PHP
CentOS 安装 PHP5.5+Redis+XDebug+Nginx+MySQL全纪录
Mar 25 PHP
PHP浮点数精度问题汇总
May 13 PHP
基于php的CMS中展示文章类实例分析
Jun 18 PHP
laravel5.2实现区分前后台用户登录的方法
Jan 11 PHP
微信公众平台开发教程③ PHP实现微信公众号支付功能图文详解
Apr 10 PHP
php中目录操作opendir()、readdir()及scandir()用法示例
Jun 08 PHP
PHP+ajax实现上传、删除、修改单张图片及后台处理逻辑操作详解
Feb 12 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无限极分类实现的两种解决方法
2013/04/28 PHP
php实现处理输入转义字符的代码
2015/11/08 PHP
PHP操作Redis常用技巧总结
2018/04/24 PHP
js 实现图片预加载(js操作 Image对象属性complete ,事件onload 异步加载图片)
2011/03/25 Javascript
改善用户体验的五款jQuery插件分享
2011/05/22 Javascript
jquery中.add()的使用分析
2013/04/26 Javascript
js实现在字符串中提取数字
2013/11/05 Javascript
JS 去除Array中的null值示例代码
2013/11/20 Javascript
从零学JSON之JSON数据结构
2014/05/19 Javascript
JavaScript的类型、值和变量小结
2015/07/09 Javascript
jQuery版本升级踩坑大全
2016/01/12 Javascript
jquery自定义右键菜单、全选、不连续选择
2016/03/01 Javascript
关于原生js中bind函数的简单实现
2016/08/10 Javascript
JS定时器用法分析【时钟与菜单中的应用】
2016/12/21 Javascript
Node.js连接MongoDB数据库产生的问题
2017/02/08 Javascript
详解webpack进阶之loader篇
2017/08/23 Javascript
vue组件jsx语法的具体使用
2018/05/21 Javascript
three.js实现圆柱体
2018/12/30 Javascript
详解JSON和JSONP劫持以及解决方法
2019/03/08 Javascript
JavaScript高阶教程之“==”隐藏下的类型转换
2019/04/11 Javascript
JS中数组实现代码(倒序遍历数组,数组连接字符串)
2019/12/29 Javascript
jquery自定义组件实例详解
2020/12/31 jQuery
[05:09]第二届DOTA2亚洲邀请赛决赛日比赛集锦:iG 3:0 OG夺冠
2017/04/05 DOTA
[01:20]PWL S2开团时刻第三期——团战可以输 蝙蝠必须死
2020/11/26 DOTA
Python迭代器与生成器用法实例分析
2018/07/09 Python
python入门之基础语法学习笔记
2020/02/08 Python
利用python批量爬取百度任意类别的图片的实现方法
2020/10/07 Python
详解CSS3选择器:nth-child和:nth-of-type之间的差异
2017/09/18 HTML / CSS
骆驼官方商城:CAMEL
2016/11/22 全球购物
关于VPN
2012/06/10 面试题
linux面试题参考答案(4)
2014/09/21 面试题
经济学博士求职自荐信范文
2013/11/23 职场文书
关于中国梦的演讲稿
2014/04/23 职场文书
应聘教师自荐书
2014/06/16 职场文书
小学六年级班主任工作经验交流材料
2015/11/02 职场文书
OpenCV中resize函数插值算法的实现过程(五种)
2021/06/05 Python