php引用传值与传值赋值的copy on write,简单底层原理

 php中的引用传值与传值赋值在内存中的操作是不一样的,php有个cow机制,当然很多语言都有,对于传值赋值的来说进行赋值时并不会在内存中开辟新的空间,只有原值发生改变时,才会开辟新空间,比如:$a = 5;  $b = $a; 这是不会开辟$b的空间,而是把$b指向$a的空间,而当再次给$a赋值时,如再次写$a=5;这是才会开辟新空间。可以使用php的

memory_get_usage()函数来查看内存的变化。


而当使用引用传值时,两个变量一直指向的是同一块内存空间,即使给原变量修改值,也不会重新开辟内存空间,两个变量同时指向新值的地址而已。仍然可以使用Memory_get_usage()函数来查看内存使用情况,发现内存使用情况并没有明显变化、因为此时已经没有了COW机制。


众所周知php使用的是zend引擎来解析Php变量,而在zend引擎中解析变量时存在一个zval的结构,通过查看这个zval结构就能简单看出php的两种赋值形式的底层实现。


如果想简单查看底层实现原理,可以借助xdebug来简单查看,如 xdebug_debug_zval();

$a = 5;

xdebug_debug_zval($a);

$b = &$a;

xdebug_debug_zval($a);


$a = 6;


xdebug_debug_zval($a);


通过打印这个demo就能看出refcount的值,代表指向同一个内存块的变量的数量。这个会一直是2,而is_ref会变为1(true),代表是引用传值。


再来看看unset


当使用引用传值时,使用unset掉一个变量,内存空间并不会被销毁,只会取消该变量到内存地址的指向。


对于对象来说, 在php当中对象默认就是引用传值,所以即使是$a=5;$a=$b,$a=6,这样的修改操作发生,refcount仍然是为2,但是Is_ref为0,这点需要注意,对象虽然默认为引用传递,但是并不是显示的,所以is_ref为0.比如:

class persion{

piblic $name='zhangsan';

}

$a = new persion;

使用xdebug来查看$a在内存中使用:

xdebug_debug_zval($a);


$b = $a;

xdebug_debug_zval($a);


$a->name = 'lisi'; (进行了cow的操作)

xdebug_debug_zval($a);


执行后会发现refcount除了第一次为1外,后面一直为2,说明两个对象变量虽然进行了cow操作,但是也没有开辟新的内存空间,而且无论是$a还是$b对象,name值均发生了变化。因为他们指向的是同一块内存空间。


所以说对象有对象的特殊性,它的赋值不会进行内存空间的复制,如果想要进行空间复制可以使用的是clone.














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值