美文网首页程序员
php7的写时复制机制

php7的写时复制机制

作者: 跑马溜溜的球 | 来源:发表于2020-09-02 14:49 被阅读0次

1. 什么是写时复制

《php7引用计数》的文章中,我们知道,对于复制类型的变量,在赋值时,我们并没有重新复制一份数据,而是让新变量的zend_value中相应的指针指向原来的数据,同时增加引用计数。

赋值后,如果其中一个变量试图改变数据内容,就需要重新拷贝一份原数据,同时断开zend_value指向,并改变引用计数。这个过程我们称为写时复制。

下面来看一个例子:

$a = range(0,2);
$b = $a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

echo "after write\n";
$b[1] = 88;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

输出:

a: (refcount=2, is_ref=0)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2)
b: (refcount=2, is_ref=0)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2)
after write
a: (refcount=1, is_ref=0)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=1, 2 => (refcount=0, is_ref=0)=2)
b: (refcount=1, is_ref=0)=array (0 => (refcount=0, is_ref=0)=0, 1 => (refcount=0, is_ref=0)=88, 2 => (refcount=0, is_ref=0)=2)

说明:

  • 赋值后,a,b指向同一个zend_array。引用计数为2。
    $b=$a
  • b时行修改时,发生写时复制,b复制一份新的zend_array,再对b[1]进行修改,因为两者引用计数都变成1。此时如果查看a, 它的内容是没有改变的。
    修改$b

2. 所有变量都会发生写时复制么?

不是所有类型的变量都可以发生写时复制。

|     type       |  copyable  |
+----------------+------------+
|simple types    |            |
|string          |      Y     |
|interned string |            |
|array           |      Y     |
|immutable array |            |
|object          |            |
|resource        |            |
|reference       |            |

如上表所示,只有string和array类型的变量,会发生写时复制。
zval.u1.type_flag中记录了当前变量是否可以进行copy。

#define IS_TYPE_COPYABLE         (1<<4)

3. 写时复制的启示

理解写时复制对于理解array, string, object类型的赋值修改,及做为函数参数传递后的修改特别重要。

下面我们看一个object的例子:

class Demo{
    public $name = 'y';
}

$a = new Demo();
$b = $a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');

$b->name = 'x';
xdebug_debug_zval('a');
xdebug_debug_zval('b');

输出:

a: (refcount=2, is_ref=0)=class Demo { public $name = (refcount=0, is_ref=0)='y' }
b: (refcount=2, is_ref=0)=class Demo { public $name = (refcount=0, is_ref=0)='y' }
a: (refcount=2, is_ref=0)=class Demo { public $name = (refcount=0, is_ref=0)='x' }
b: (refcount=2, is_ref=0)=class Demo { public $name = (refcount=0, is_ref=0)='x' }

说明:

  • b =a后,两者指向是一个zend_object, 引用计数为2。
  • 因为object类型不会发生写时复制,所以修改b的name值,等同于修改a的name值。因此我们看到,修改后,引用计数仍然为2, a,b的name属性值都变为x。

同理,你可以得出下面一段代码的输出为"ball"。

class Demo{
    public $name = 'y';
}

$a = new Demo();
$b = $a;

function change($obj){
    $obj->name = "ball";
}

change($a);
echo $b->name;

对于array和string类型,因为必会发生写时复制,所以任何情况下对其内部元素的修改都不会影响原值。

结论:

类型 赋值后修改 作为函数参数修改
object 原值改变 原值改变
string 原值不变 原值不变
array 原值不变 原值不变

相关文章

  • php7的写时复制机制

    1. 什么是写时复制 在《php7引用计数》的文章中,我们知道,对于复制类型的变量,在赋值时,我们并没有重新复制一...

  • linux系统编程-day10-进程管理(2)

    vfork( ): 上节学习了fork( )时的写时复制机制,实际上在早期并没有实现写时复制,在实现COW之前,U...

  • SAP ABAP 的两种内存对象类型

    要研究 SAP ABAP 内表的写时复制(copy on write)机制,ABAP Memory Inspect...

  • Linux0.11缓冲区机制详解

    相关阅读(点击即可阅读哦~):Linux0.11写时复制机制详解LINUX0.11信号机制Linux0.11共享内...

  • Linux0.11写时复制机制详解

    当执行fork时,子进程除了通过get_free_page申请到一个页面用来存放内核栈和任务数据结构,子进程复制父...

  • 写时复制

    简介 写入时复制是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者同时请求相同资源(如内存或磁盘上...

  • 写时复制

    现在有一个父进程P1,这是一个主体,那么它是有灵魂也就身体的。现在在其虚拟地址空间(有相应的数据结构表示)上有:正...

  • 写时复制

    写时复制 在swift中,像Array、Dictionary、Set等集合类型都是通过写时复制(copy-on-w...

  • (二十) copyonwrite

    一、copyonwrite机制 写时复制:1、添加数据时,先拷贝存储的数组,,2、用现在(拷好)数组替换 成员变量...

  • 科技爱好者摘录 番外篇 一

    1. Copy On Write机制了解一下 一篇关于写时复制机制的介绍,比较清晰基础,而且文章还列举了许多网上其...

网友评论

    本文标题:php7的写时复制机制

    本文链接:https://www.haomeiwen.com/subject/ichwsktx.html