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 相关文章推荐
如何做到多笔资料的同步
Oct 09 PHP
我的论坛源代码(十)
Oct 09 PHP
php中使用exec,system等函数调用系统命令的方法(不建议使用,可导致安全问题)
Sep 07 PHP
ThinkPHP框架任意代码执行漏洞的利用及其修复方法
Jul 04 PHP
在Ubuntu 14.04上部署 PHP 环境及 WordPress
Sep 02 PHP
php绘图之生成饼状图的方法
Jan 24 PHP
PHP实现递归复制整个文件夹的类实例
Aug 03 PHP
PHP函数引用返回的实例详解
Sep 11 PHP
thinkphp跨库操作的简单代码实例
Sep 22 PHP
PHP依赖注入(DI)和控制反转(IoC)详解
Jun 12 PHP
PHP+Redis 消息队列 实现高并发下注册人数统计的实例
Jan 29 PHP
Laravel 加载第三方类库的方法
Apr 20 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字符串处理的10个简单方法
2010/06/30 PHP
PHP extract 将数组拆分成多个变量的函数
2010/06/30 PHP
php 模拟GMAIL,HOTMAIL(MSN),YAHOO,163,126邮箱登录的详细介绍
2013/06/18 PHP
Thinkphp通过一个入口文件如何区分移动端和PC端
2017/04/18 PHP
PHP 实现页面静态化的几种方法
2017/07/23 PHP
JS 字符串连接[性能比较]
2009/05/10 Javascript
jQuery.lazyload+masonry改良图片瀑布流代码
2014/06/20 Javascript
js数组去重的方法汇总
2015/07/29 Javascript
jQuery实现响应鼠标事件的图片透明效果【附demo源码下载】
2016/06/16 Javascript
Jquery循环截取字符串的方法(多出的字符串处理成&quot;...&quot;)
2016/11/28 Javascript
Ajax异步获取html数据中包含js方法无效的解决方法
2017/02/20 Javascript
用Node编写RESTful API接口的示例代码
2018/07/04 Javascript
vue 中引用gojs绘制E-R图的方法示例
2018/08/24 Javascript
Vue实现移动端左右滑动效果的方法
2018/11/27 Javascript
全面分析JavaScript 继承
2019/05/30 Javascript
文章或博客自动生成章节目录索引(支持三级)的实现代码
2020/05/10 Javascript
详解Swift中属性的声明与作用
2016/06/30 Python
使用python在本地电脑上快速处理数据
2017/06/22 Python
python 垃圾收集机制的实例详解
2017/08/20 Python
Python日期时间模块datetime详解与Python 日期时间的比较,计算实例代码
2018/09/14 Python
Python3中_(下划线)和__(双下划线)的用途和区别
2019/04/26 Python
django-rest-swagger的优化使用方法
2019/08/29 Python
在python中实现求输出1-3+5-7+9-......101的和
2020/04/02 Python
python logging.info在终端没输出的解决
2020/05/12 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
2020/05/20 Python
基于Python实现2种反转链表方法代码实例
2020/07/06 Python
大学毕业自我评价
2014/02/02 职场文书
大学生2014全国两会学习心得体会
2014/03/10 职场文书
退休教师欢送会主持词
2014/03/31 职场文书
感恩母亲节演讲稿
2014/05/07 职场文书
公司开业庆典策划方案
2014/06/04 职场文书
2014世界杯球队球队口号
2014/06/05 职场文书
法人授权委托书范本
2014/09/17 职场文书
房地产项目合作意向书
2015/05/08 职场文书
2016年精神文明建设先进个人事迹材料
2016/02/29 职场文书
css实现左上角飘带效果的完整代码
2022/03/18 HTML / CSS