PHP copy on write 写时复制机制

就是在写入时才真正复制一份内存进行修改,举例:

$i = 4;   
//内核创建一个zval指针,并且为其以堆的方式开辟空间,让指针指向这个空间,
//将zval中的成员引用计数置为1,类型标记为整形,并且申请一个zvalue_value指针,
//同样以堆的方式以其开辟空间,同时将该联合体中的lval赋值为4,
//并且在symbal_table的hash表中记录变量i和zval指针的映射关系
$j = $i;   //没有在申请内存空间,在zval的成员中引用计数标记为2
$j = 5;   //内核重新创建zval指针,重复下上面的步骤,我就不重复说明了,重点是将旧的zval引用计数标记为1

在复制一个对象的时候并不是真正的把原先的对象复制到内存的另外一个位置上,而是在新对象的内存映射表中设置一个指针,指向源对象的位置,并把那块内存的Copy-On-Write位设置为1.这样,在对新的对象执行读操作的时候,内存数据不发生任何变动,直接执行读操作;而在对新的对象执行写操作时,将真正的对象复制到新的内存地址中,并修改新对象的内存映射表指向这个新的位置,并在新的内存位置上执行写操作
这个技术需要跟虚拟内存和分页同时使用,好处就是在执行复制操作时因为不是真正的内存复制,而只是建立了一个指针,因而大大提高效率。但这不是一直成立的,如果在复制新对象之后,大部分对象都还需要继续进行写操作会产生大量的分页错误,得不偿失。所以COW高效的情况只是在复制新对象之后,在一小部分的内存分页上进行写操作。
PHP中数组和对象都为地址传参,对象是可以正常理解的,但是数组跟理解的有些差异。
数组是通过引用传递的,除非它在你调用的方法/函数中被修改。如果您尝试在方法/函数中修改数组,则首先创建它的副本,然后仅修改副本。这使得它看起来好像数组是按值传递的,而事实上并非如此。这被称为“懒惰副本”或“写入时复制”。
参考: