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 相关文章推荐
加速XP搜索功能堪比vista
Mar 22 PHP
PHP和XSS跨站攻击的防范
Apr 17 PHP
PHP 的异常处理、错误的抛出及回调函数等面向对象的错误处理方法
Dec 07 PHP
PHP实现的json类实例
Jul 28 PHP
PHP页面转UTF-8中文编码乱码的解决办法
Oct 20 PHP
WordPress中自定义后台管理界面配色方案的小技巧
Dec 29 PHP
php图片添加水印例子
Jul 20 PHP
Laravel框架中自定义模板指令总结
Dec 17 PHP
php处理多图上传压缩代码功能
Jun 13 PHP
PHP mongodb操作类定义与用法示例【适合mongodb2.x和mongodb3.x】
Jun 16 PHP
Linux基于php-fpm模式的lamp搭建phpmyadmin的方法
Oct 25 PHP
imagettftext() 失效,不起作用
Mar 09 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
phpBB BBcode处理的漏洞
2006/10/09 PHP
PHP自动更新新闻DIY
2006/10/09 PHP
解析php中用PHPMailer来发送邮件的示例(126.com的例子)
2013/06/24 PHP
php程序员应具有的7种能力小结
2014/11/27 PHP
php把大写命名转换成下划线分割命名
2015/04/27 PHP
Yii2学习笔记之汉化yii设置表单的描述(属性标签attributeLabels)
2017/02/07 PHP
PHP实现从上往下打印二叉树的方法
2018/01/18 PHP
PHP命名空间简单用法示例
2018/12/28 PHP
laravel 使用事件系统统计浏览量的实现
2019/10/16 PHP
laravel 实现用户登录注销并限制功能
2019/10/24 PHP
js+数组实现网页上显示时间/星期几的实用方法
2013/01/18 Javascript
Jquery实现点击按钮,连续地向textarea中添加值的实例代码
2014/03/08 Javascript
JavaScript中constructor()方法的使用简介
2015/06/05 Javascript
JavaScript实战之带收放动画效果的导航菜单
2016/08/16 Javascript
vue.js入门教程之绑定class和style样式
2016/09/02 Javascript
jQuery实现frame之间互通的方法
2017/06/26 jQuery
Webpack devServer中的 proxy 实现跨域的解决
2018/06/15 Javascript
javascript数组去重方法总结(推荐)
2019/03/20 Javascript
如何实现iframe父子传参通信
2020/02/05 Javascript
[40:16]TFT vs Mski Supermajor小组赛C组 BO3 第二场 6.3
2018/06/04 DOTA
python中的yield使用方法
2014/02/11 Python
Python实现删除当前目录下除当前脚本以外的文件和文件夹实例
2015/07/27 Python
python编程实现希尔排序
2017/04/13 Python
Django使用HttpResponse返回图片并显示的方法
2018/05/22 Python
python实时获取外部程序输出结果的方法
2019/01/12 Python
python自动化UI工具发送QQ消息的实例
2019/08/27 Python
详解python opencv、scikit-image和PIL图像处理库比较
2019/12/26 Python
pytorch 利用lstm做mnist手写数字识别分类的实例
2020/01/10 Python
五种Python转义表示法
2020/11/27 Python
8款使用 CSS3 实现超炫的 Loading(加载)的动画效果
2015/03/17 HTML / CSS
大学生活动总结怎么写
2014/04/29 职场文书
革命英雄事迹演讲稿
2014/09/13 职场文书
2015年药店店长工作总结
2015/04/29 职场文书
出生证明格式
2015/06/15 职场文书
暑期工社会实践报告
2015/07/13 职场文书
优秀范文:《但愿人长久》教学反思3篇
2019/10/24 职场文书