您的位置:首页 > 编程语言 > PHP开发

PHP写时复制(Copy-on-Write)

2014-04-21 00:00 771 查看
说到PHP的垃圾回收机制引用计数器和写时复制是不得不说的,引用计数器就是让写时复制正常工作的保证,它们是PHP的主要优化手段。【推荐阅读PHP引用计数器
在教程之前,希望大家能够完全理解zval变量容器中的ref_count和is_ref

is_ref标识是不是用户使用 & 的强制引用;
ref_count是引用计数,用于标识此zval被多少个变量引用,即COW的自动引用,为0时会被销毁;

写时复制(Copy-on-Write)概念:
简单的理解就是资源延时分配,如下代码:
<?php
 $a = 1;
 $b = $a;


PHP中的变量是用一个存储在symbol_table中的符号名,对应一个zval来实现的,比如对于上面的第一行代码,会在symbol_table中存储一个值”a”, 对应的有一个指针指向一个zval结构,变量值“1”会被保存在zval中,实际上$a和$b都是指向同一个zval就实现了节省资源的目的,特点是在大数组复制等场景下会节省很多内存,但变量的值一旦发生变化,指向的zval就是变化。

写时复制(Copy-on-Write)实现:
于是就引入了is_ref和ref_count两个标志,看下面简单代码:
$a = 1;
//为什么是2呢?当执行debug_zval_dump($var)的时候,
//$var会以传值的方式传递给debug_zval_dump,也就是会导致var的refcount加1
debug_zval_dump($a);  //long(1) refcount(2)
$b = $a;

//必然的是:当一个变量复制给另一个变量会导致zval的recount加1
debug_zval_dump($a);  //long(1) refcount(3)


如果改变一个变量的值呢?
$a = 1;
//为什么是2呢?当执行debug_zval_dump($var)的时候,
//$var会以传值的方式传递给debug_zval_dump,也就是会导致var的refcount加1
debug_zval_dump($a);  //long(1) refcount(2)
$b = $a;

//必然的是:当一个变量复制给另一个变量会导致zval的recount加1
debug_zval_dump($a);  //long(1) refcount(3)

$a = 'http://www.phpddt.com';

debug_zval_dump($a); // string(21) "http://www.phpddt.com" refcount(2)
debug_zval_dump($b); //long(1) refcount(2)


PHP在修改一个变量以前,会首先查看这个变量的refcount,如果refcount大于1,PHP就会执行分离,如上,PHP发现$a指向的zval的refcount大于1,那么PHP就会复制一个新的zval出来,将原zval的refcount减1,并修改symbol_table,使得$a和$b分离(Separation)。这个机制就是所谓的copy on write(写时复制)。
看一个复杂点的ref_count和is_ref变化的例子:


参考资料:
(1)PHP手册:http://www.phpddt.com/manual/php/res/features.gc.refcounting-basics.html
(2)http://www.php-internals.com/book/?p=chapt06/06-06-copy-on-write
(3)http://www.laruence.com/2008/09/19/520.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: