1.使用memory_get_usage()查看PHP内存使用情况1.赋值//定义一个变量$a=range(0,10000);var_dump(memory_get_usage());//定义变量b,将变量a的值赋给b$b=$a;var_dump(memory_get_usage());//修改a//COW:Copy-On-Write$a=range(0,10000);var_dump(memory_get_usage());输出结果:int(989768)int(989856)int(1855608)定义一个变量$a=range(0,10000);$b=$a;修改$a=range(0,10000);PHP的写时复制机制(Copy-on-Write,也简称为COW)顾名思义,就是在写的时候实际复制一份内存用于修改。COW最早应用于Unix系统,用于优化线程和内存的使用,后来广泛应用于各种编程语言,如C++STL等。在PHP核心中,COW也是主要的内存优化方式。通过变量赋值的方式给变量赋值时,并不会申请新的内存来存储新变量的值,只是简单地使用一个计数器来共享内存。只有当其中一个引用指向的变量的值发生变化时,才会申请新的空间来保存值内容,从而减少内存占用。在很多场景下,PHP使用COW来进行内存优化。例如:变量的多次赋值、函数参数传递、在函数体中修改实参等。2.引用赋值//定义一个变量$a=range(0,10000);var_dump(memory_get_usage());//定义变量b,将变量a的引用赋值给b$b=&$a;var_dump(memory_get_usage())());//修改a$a=range(0,10000);var_dump(memory_get_usage());输出:int(989760)int(989848)int(989840)定义一个变量$a=range(0,10000);定义变量b,将变量a的引用赋值给b$b=&$a;修改$a=range(0,10000);2、使用xdebug_debug_zval()检查变量的引用xdebug_debug_zval()用于显示变量信息。需要安装xdebug扩展。1.赋值$a=1;xdebug_debug_zval('a');//定义变量b,将a的值赋给b$b=$a;xdebug_debug_zval('a');xdebug_debug_zval('b');//写操作$a=2;xdebug_debug_zval('a');xdebug_debug_zval('b');输出结果:a:(refcount=1,is_ref=0)=1a:(refcount=2,is_ref=0)=1b:(refcount=2,is_ref=0)=1a:(refcount=1,is_ref=0)=2b:(refcount=1,is_ref=0)=1定义变量$a=1;$a=1;xdebug_debug_zval('a');outputa:(refcount=1,is_ref=0)=1refcount=1表示变量指向的内存地址的引用次数变为1is_ref=0表示变量不是引用定义变量$b,赋值$a到$b,$b=$a;$b=$a;xdebug_debug_zval('a');xdebug_debug_zval('b');outputa:(refcount=2,is_ref=0)=1b:(refcount=2,is_ref=0)=1refcount=2表示变量指向的内存地址的引用次数变为2is_ref=0表示变量不是引用写入变量$a$a=2;$a=2;xdebug_debug_zval('a');xdebug_debug_zval('b');输出a:(refcount=1,is_ref=0)=2b:(refcount=1,is_ref=0)=1因为COW机制,变量$a在执行写操作时,会分配一块新的内存空间给变量$a存储变量$a的值。此时$a和$b指向的内存地址的引用号都变为1。2.引用赋值$a=1;xdebug_debug_zval('a');//定义变量b,将a的引用赋值给b$b=&$a;xdebug_debug_zval('a');xdebug_debug_zval('b');//写操作$a=2;xdebug_debug_zval('a');xdebug_debug_zval('b');a:(refcount=1,is_ref=0)=1a:(refcount=2,is_ref=1)=1b:(refcount=2,is_ref=1)=1a:(refcount=2,is_ref=1)=2b:(refcount=2,is_ref=1)=2定义变量$a=1;$a=1;xdebug_debug_zval('A');outputa:(refcount=1,is_ref=0)=1refcount=1表示变量指向的内存地址的引用次数变为1is_ref=0表示变量不是引用定义变量$b,set$a引用赋值给$b,$b=&$a;$b=&$a;xdebug_debug_zval('a');xdebug_debug_zval('b');outputa:(refcount=2,is_ref=1)=1b:(refcount=2,is_ref=1)=1refcount=2表示变量指向的内存地址的引用次数变为2.is_ref=1表示该变量是写入变量$a$a=2的引用;$a=2;xdebug_debug_zval('a');xdebug_debug_zval('b');输出a:(refcount=2,is_ref=1)=2b:(refcount=2,is_ref=1)=2因为变量$a和变量$b指向同一个内存地址,实际上被引用了。当变量$a被写入时,指向的内存空间的值会被直接修改,所以变量$b的值也会随之改变。3.变量被引用时,unset()只会解引用,不会破坏内存空间$a=1;$b=&$a;//unset只会解引用,不会破坏内存空间unset($b);回声$a;输出1定义变量$a,并将$a的引用赋值给变量$b$a=1;$b=&$a;销毁$bunset($b);输出$a虽然销毁了$b,但是$a的引用和内存空间依然存在。回声$a;输出1四、php中对象本身就是引用赋值classPerson{public$age=1;}$p1=newPerson;xdebug_debug_zval('p1');$p2=$p1;xdebug_debug_zval('p1');xdebug_debug_zval('p2');$p2->age=2;xdebug_debug_zval('p1');xdebug_debug_zval('p2');p1:(refcount=1,is_ref=0)=classPerson{public$age=(refcount=2,is_ref=0)=1}p1:(refcount=2,is_ref=0)=classPerson{public$age=(refcount=2,is_ref=0)=1}p2:(refcount=2,is_ref=0)=classPerson{public$age=(refcount=2,is_ref=0)=1}p1:(refcount=2,is_ref=0)=classPerson{public$age=(refcount=1,is_ref=0)=2}p2:(refcount=2,is_ref=0)=classPerson{public$age=(refcount=1,is_ref=0)=2}实例化对象$p1=newPerson;$p1=newPerson;xdebug_debug_zval('p1');outputp1:(refcount=1,is_ref=0)=classPerson{public$age=(refcount=2,is_ref=0)=1}refcount=1表示变量指向的内存地址引用数变为1is_ref=0,表示该变量不是引用。将$p1分配给$p2$p2=$p1;xdebug_debug_zval('p1');xdebug_debug_zval('p2');输出p1:(refcount=2,is_ref=0)=classPerson{public$age=(refcount=2,is_ref=0)=1}p2:(refcount=2,is_ref=0)=classPerson{public$age=(refcount=2,is_ref=0)=1}refcount=2表示指向的变量内存地址引用数变为2,在$p2中写入属性age$p2->age=2;xdebug_debug_zval('p1');xdebug_debug_zval('p2');输出p1:(refcount=2,is_ref=0)=classPerson{public$age=(refcount=1,is_ref=0)=2}p2:(refcount=2,is_ref=0)=classPerson{public$age=(refcount=1,is_ref=0)=2}因为php中的对象本身是引用赋值,$p2中的属性age写入时,指向的内存空间的值会被直接修改,所以的值变量$p1的age属性将相应改变。5.实战实例分析/***写出如下程序的输出**$d=['a','b','c'];**foreach($das$k=>$v)*{*$v=&$d[$k];*}**程序运行时,每次循环结束后变量$d的值是多少?请解释。*程序执行完后变量$d的值是多少?请解释。*/1。第一个循环在进入foreach时计算$v和$d[$k]的值$k=0$v='a'$d[$k]=$d[0]='a'此时,$v和$d[0]分别在内存中开辟了空间![$v和$d[0]分别在内存中开辟了空间](http://md.ws65535.top/xsj/201...$v=&$d[0]改变$v指向的内存地址$v=&$d[0]![$v=&$d[0]改变$val指向的内存地址](http://md.ws65535.top/xsj/201...第一次循环后$d的值:['a','b','c']2.当第二次循环进入foreach时$v为赋值'b',此时$v指向的内存地址与$d[0]相同,是引用,所以$d[0]的值修改为'b'$v='b'=>$d[0]='b'![$v='b'=>$d[0]='b'](http://md.ws65535.top/xsj/201...计算输入foreach中$d[$k]的值$k=1$d[$k]=$d[1]='b'![$d[2]='b'](http://md.ws65535.top/xsj/201...$v=&$d[1]改变$v指向的内存地址$v=&$d[1]![$v=&$d[1]](http://md.ws65535.top/xsj/201...第二次循环后$d的值['b','b','c']3.第三次循环进入foreach时,$v被赋值为'c',在这次$v指向的内存地址和$d[1]一样,都是引用,所以$d[1]的值修改为'c'$v='c'=>$d[1]='c'![$v='c'=>$d[1]='c'](http://md.ws65535.top/xsj/201...估计是$d[当输入foreach时$k的值]$k=2$d[2]='c'![$d[2]='c'](http://md.ws65535.top/xsj/201...$v=&$d[2]改变$v指向的内存地址$v=&$d[2]![$v=&$d[2]](http://md.ws65535.top/xsj/201...第三次循环后$d的值['b','c','c']4.Measured$d=['a','b','c'];foreach($das$k=>$v){$v=&$d[$k];print_r($d);}print_r($d);输出:Array([0]=>a[1]=>b[2]=>c)数组([0]=>b[1]=>b[2]=>c)数组([0]=>b[1]=>c[2]=>c)数组([0]=>b[1]=>c[2]=>c)
