当前位置:  编程技术>php

PHP 之 写时复制介绍(Copy On Write)

    来源: 互联网  发布时间:2014-08-26

    本文导语:  在开始之前,我们可以先看一段简单的代码: 代码如下:  执行这段代码,会打印出数字2。从内存的角度来分析一下这段代码“可能”是这样执行的:分配一块内存给foo变量,里面存储一个1; 再分配一块内存给bar变量,也存...

在开始之前,我们可以先看一段简单的代码:

代码如下:


 执行这段代码,会打印出数字2。从内存的角度来分析一下这段代码“可能”是这样执行的:分配一块内存给foo变量,里面存储一个1; 再分配一块内存给bar变量,也存一个1,最后计算出结果输出。事实上,我们发现foo和bar变量因为值相同,完全可以使用同一块内存,这样,内存的使用就节省了一个1,并且,还省去了分配内存和管理内存地址的计算开销。没错,很多涉及到内存管理的系统,都实现了这种相同值共享内存的策略:写时复制

很多时候,我们会因为一些术语而对其概念产生莫测高深的恐惧,而其实,他们的基本原理往往非常简单。本小节将介绍PHP中写时复制这种策略的实现:

写时复制(Copy on Write,也缩写为COW)的应用场景非常多, 比如Linux中对进程复制中内存使用的优化,在各种编程语言中,如C++的STL等等中均有类似的应用。 COW是常用的优化手段,可以归类于:资源延迟分配。只有在真正需要使用资源时才占用资源, 写时复制通常能减少资源的占用。

注: 为节省篇幅,下文将统一使用COW来表示“写时复制”;

推迟内存复制的优化

       正如前面所说,PHP中的COW可以简单描述为:如果通过赋值的方式赋值给变量时不会申请新内存来存放新变量所保存的值,而是简单的通过一个计数器来共用内存,只有在其中的一个引用指向变量的值发生变化时才申请新空间来保存值内容以减少对内存的占用。在很多场景下PHP都COW进行内存的优化。比如:变量的多次赋值、函数参数传递,并在函数体内修改实参等。

下面让我们看一个查看内存的例子,可以更容易看到COW在内存使用优化方面的明显作用:

代码如下:


//-----执行结果-----
foo: (refcount=1, is_ref=0)=1
foo: (refcount=2, is_ref=0)=1
foo: (refcount=1, is_ref=0)=1

  经过前面对变量章节的介绍,我们知道当$foo被赋值时,$foo变量的值的只由$foo变量指向。当$foo的值被赋给$bar时,PHP并没有将内存复制一份交给$bar,而是把$foo和$bar指向同一个地址。同时引用计数增加1,也就是新的2。随后,我们更改了$bar的值,这时如果直接需该$bar变量指向的内存,则$foo的值也会跟着改变。这不是我们想要的结果。于是,PHP内核将内存复制出来一份,并将其值更新为赋值的:2(这个操作也称为变量分离操作),同时原$foo变量指向的内存只有$foo指向,所以引用计数更新为:refcount=1。

        看上去很简单,但由于&运算符的存在,实际的情形要复杂的多。见下面的例子:




图6.6 &操作符引起的内存复制分离>

从这个例子可以看出PHP对&运算符的一个容易出问题的处理:当 $beauty=&$pan; 时,两个变量本质上都变成了引用类型,导致看上去的普通变量$pan, 在某些内部处理中与&$pan行为相同,尤其是在数组元素中使用引用变量,很容易引发问题。(见最后的例子)

       PHP的大多数工作都是进行文本处理,而变量是载体,不同类型的变量的使用贯穿着PHP的生命周期,变量的COW策略也就体现了Zend引擎对变量及其内存处理,具体可以参阅源码文件相关的内容:

代码如下:

Zend/zend_execute.c
========================================
    zend_assign_to_variable_reference();
    zend_assign_to_variable();
    zend_assign_to_object();
    zend_assign_to_variable();

//以及下列宏定义的使用
Zend/zend.h
========================================
    #define Z_REFCOUNT(z)           Z_REFCOUNT_P(&(z))
    #define Z_SET_REFCOUNT(z, rc)       Z_SET_REFCOUNT_P(&(z), rc)
    #define Z_ADDREF(z)         Z_ADDREF_P(&(z))
    #define Z_DELREF(z)         Z_DELREF_P(&(z))
    #define Z_ISREF(z)          Z_ISREF_P(&(z))
    #define Z_SET_ISREF(z)          Z_SET_ISREF_P(&(z))
    #define Z_UNSET_ISREF(z)        Z_UNSET_ISREF_P(&(z))
    #define Z_SET_ISREF_TO(z, isref)    Z_SET_ISREF_TO_P(&(z), isref)

最后,请慎用引用&

       引用和前面提到的变量的引用计数和PHP中的引用并不是同一个东西,引用和C语言中的指针的类似,他们都可以通过不同的标示访问到同样的内容,但是PHP的引用则只是简单的变量别名,没有C指令的灵活性和限制。

      PHP中有非常多让人觉得意外的行为,有些因为历史原因,不能破坏兼容性而选择暂时不修复,或者有的使用场景比较少。在PHP中只能尽量的避开这些陷阱。例如下面这个例子。

      由于引用操作符会导致PHP的COW策略优化,所以使用引用也需要对引用的行为有明确的认识才不至于误用,避免带来一些比较难以理解的的Bug。如果您认为您已经足够了解了PHP中的引用,可以尝试解释下面这个例子:

代码如下:


    
 
 

您可能感兴趣的文章:

  • PHP中copy on write写时复制机制介绍
  • PHP介绍及学习网站推荐
  • PHP strip_tags()去除HTML、XML以及PHP的标签介绍
  • php session_id()函数介绍及代码实例
  • 设置php页面编码的两种方法示例介绍
  • php中检测变量是否是一个对象的is_object函数介绍及用法举例
  • PHP include任意文件或URL介绍
  • php中session_id()函数详细介绍,会话id生成过程及session id长度
  • PHP COOKIE及时生效的方法介绍
  • php会话(session)生命周期概念介绍及设置更改和回收
  • php pdo mysql query用法介绍
  • php将html特殊字符转换成html字符串的函数:htmlspecialchars()介绍及代码举例
  • php中的路径问题与set_include_path使用介绍
  • PHP编程语言介绍及安装测试方法
  • PHP字符串的递增和递减示例介绍
  • php 5.5.14数据对象(PDO)介绍及PDO的预定义常量介绍
  • PHP函数eval()介绍和使用示例
  • php session 原理详解,用法介绍以及如何设置过期时间
  • PHP eval函数使用介绍
  • Apache HTTP Server(httpd)下载安装以及如何配置java(tomcat)和php详细介绍
  • PHP fopen()和 file_get_contents()应用与差异介绍
  • php时间格式化函数date介绍及用法参考
  • PHP ini_set的用法介绍
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 修改配置真正解决php文件上传大小限制问题(nginx+php)
  • IIS7配置PHP图解(IIS7+PHP_5.2.17/PHP_5.3.5)
  • PHP 5.4.19 和 PHP 5.5.3 发布及下载地址
  • php输入流php://input使用示例(php发送图片流到服务器)
  • 修改配置真正解决php文件上传大小限制问题(apache+php)
  • PHP转换器 HipHop for PHP
  • PHP去除html标签,php标记及css样式代码参考
  • PHP 框架 Pop php
  • PHP 'ext/soap/php_xml.c'不完整修复存在多个任意文件泄露漏洞
  • PHP的JavaScript框架 PHP.JS
  • php通过socket_bind()设置IP地址代码示例
  • php服务器探针显示php服务器信息
  • php安装完成后如何添加mysql扩展
  • PHP缓存加速器 Alternative PHP Cache (APC)
  • PHP的substr() 函数用法
  • PHP源文件加密工具 PHP Screw
  • php中操作memcache的类及成员列表及php下如何连接memched服务器
  • PHP自动化测试 PHP-QAT
  • php中内置的mysql数据库连接驱动mysqlnd简介及mysqlnd的配置安装方式
  • PHP 的 HTTP 客户端库 PHP Buzz
  • php将标准字符串格式时间转换成unix时间戳_strtotime
  • PHP 调试工具 PHP_Dyn




  • 特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3