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 自定义错误处理函数的使用详解
May 10 PHP
php接口与接口引用的深入解析
Aug 09 PHP
使用php显示搜索引擎来的关键词
Feb 13 PHP
浅谈php安全性需要注意的几点事项
Jul 17 PHP
一个经典的PHP验证码类分享
Nov 18 PHP
ecshop后台编辑器替换成ueditor编辑器
Mar 03 PHP
PHP+jquery+CSS制作头像登录窗(仿QQ登陆)
Oct 20 PHP
php静态成员方法和静态的成员属性的使用方法
Oct 26 PHP
PHP实现正则表达式分组捕获操作示例
Feb 03 PHP
Laravel 微信小程序后端实现用户登录的示例代码
Nov 26 PHP
php使用redis的几种常见操作方式和用法示例
Feb 20 PHP
PHP 加密 Password Hashing API基础知识点
Mar 02 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 分页原理详解
2009/08/21 PHP
Windows下的PHP 5.3.x安装 Zend Guard Loader教程
2014/09/06 PHP
php格式化金额函数分享
2015/02/02 PHP
linux下实现定时执行php脚本
2015/02/13 PHP
删除PHP数组中的重复元素的实现代码
2017/04/10 PHP
Laravel5.1 框架响应基本用法实例分析
2020/01/04 PHP
对YUI扩展的Gird组件 Part-1
2007/03/10 Javascript
location.href 在IE6中不跳转的解决方法与推荐使用代码
2010/07/08 Javascript
JavaScript1.6数组新特性介绍以及JQuery的几个工具方法
2013/12/06 Javascript
DOM基础教程之使用DOM控制表格
2015/01/20 Javascript
简单的jQuery入门指引
2015/07/28 Javascript
利用jQuery实现CheckBox全选/全不选/反选的简单代码
2016/05/31 Javascript
Vue.js 2.0学习教程之从基础到组件详解
2017/04/24 Javascript
详解vue.js+UEditor集成 [前后端分离项目]
2017/07/07 Javascript
详解nodejs的express如何自动生成项目框架
2017/07/12 NodeJs
通过js控制时间,一秒一秒自己动的实例
2017/10/25 Javascript
基于vue.js无缝滚动效果
2018/01/25 Javascript
element-ui中Table表格省市区合并单元格的方法实现
2019/08/07 Javascript
JS如何实现网站中PC端和手机端自动识别并跳转对应的代码
2020/01/08 Javascript
[42:32]DOTA2上海特级锦标赛B组资格赛#2 Fnatic VS Spirit第二局
2016/02/27 DOTA
Python获取单个程序CPU使用情况趋势图
2015/03/10 Python
python Socket之客户端和服务端握手详解
2017/09/18 Python
对python捕获ctrl+c手工中断程序的两种方法详解
2018/12/26 Python
django框架使用orm实现批量更新数据的方法
2019/06/21 Python
Python:二维列表下标互换方式(矩阵转置)
2019/12/02 Python
Python爬虫UA伪装爬取的实例讲解
2021/02/19 Python
LivingSocial爱尔兰:爱尔兰本地优惠
2018/08/10 全球购物
C语言面试题
2015/10/30 面试题
HSRP的含义以及如何工作
2014/09/10 面试题
建筑个人求职信范文
2014/01/25 职场文书
自主招生学校推荐信
2014/09/26 职场文书
村干部四风问题整改措施
2014/09/30 职场文书
自信主题班会
2015/08/14 职场文书
2016年社区植树节活动总结
2016/03/16 职场文书
分家协议书范本
2016/03/22 职场文书
MySQL 全文索引使用指南
2021/05/25 MySQL