@
543400 最近刚好在研究 PHP 内存管理方面的问题,但是如果是 C 就好了,可以很容易把内存地址打印出来,PHP 没有这么个东西来做,但是 PHP 提供了查看变量内存引用计数的函数 debug_zval_dump,配合你的代码做下分析
// 上半部分代码不变
function demoArray(){
return array(
"a"=>"我是 a",
"b"=>"我是 b",
);
};
// 把你代码下面改一下改成这样
echo "\nS.1 -----------------------\n";
debug_zval_dump(demoArray());
unset( demoArray()["a"] );
debug_zval_dump(demoArray());
echo "\nS.2 -----------------------\n";
$aa=demoArray();
debug_zval_dump(demoArray());
debug_zval_dump($aa);
echo "\nS.3 -----------------------\n";
unset($aa['a']);
debug_zval_dump(demoArray());
debug_zval_dump($aa);
对应下面的输出,下面来细说具体,下面的 refcount 就是引用数量,代表有多少个变量引用着这个变量,但是要注意的是 debug_zval_dump 函数自身会对变量产生一个引用,也就是真实的引用数量实际上是下面的数字 -1,如果 refcount - 1 = 0 了说明上下文代码中没有引用到这个变量,在 debug_zval_dump 调用结束后,他的内存就会被回收
S.1 -----------------------
代码是这样
echo "\nS.1 -----------------------\n";
debug_zval_dump(demoArray());
unset( demoArray()["a"] );
debug_zval_dump(demoArray());
输出是这样
array(2) refcount(1){
["a"]=>
string(8) "我是 a" refcount(2)
["b"]=>
string(8) "我是 b" refcount(2)
}
array(2) refcount(1){
["a"]=>
string(8) "我是 a" refcount(2)
["b"]=>
string(8) "我是 b" refcount(2)
}
这里,是用来比较 unset 对 demoArray() 的影响
可以看到 unset(demoArray()['a']) 对 demoArray() 函数的返回值没有任何的影响
也说明了每次 demoArray() 返回的结果是相互独立的
其中对于数组的 refcount = 1 是 debug_zval_dump 函数产生的,对于数组中两个元素的 refcount = 2 是数组本身对数组中变量的引用和 debug_zval_dump 函数对数组两个元素的引用
S.2 -----------------------
代码是这样
echo "\nS.2 -----------------------\n";
$aa=demoArray();
debug_zval_dump(demoArray());
debug_zval_dump($aa);
输出是这样
array(2) refcount(1){
["a"]=>
string(8) "我是 a" refcount(3)
["b"]=>
string(8) "我是 b" refcount(3)
}
array(2) refcount(2){
["a"]=>
string(8) "我是 a" refcount(2)
["b"]=>
string(8) "我是 b" refcount(2)
}
这里是看使用 $aa = demoArray() 对引用计数的影响
第一组结果:数组的引用数量还是 1 证明只有 debug_zval_dump 函数对其引用了,但是里面的数组元素的引用数变成了 3 这是因为除了第一步中说到的 debug_zval_dump() 函数,和 demoArray() 返回的数组本身对这两个元素进行了引用,还有赋值以后 $aa 这个数组,对这两个元素进行了引用( PHP 是写时复制,也就是说,在不改变变量的情况下,PHP 并不会真实的复制变量,而是对原来变量的引用计数 +1,等到真实的发生读写的时候,才会创建新的变量)
第二组结果:对于数组本身,那就是 $aa 这个变量和 debug_zval_dump 函数对其引用,所以数组的引用数是 2,但是为什么元素的引用数是 1 呢?之前直接 debug_zval_dump 输出的为什么会更多呢?因为 debug_zval_dump 输出后,没有变量接收 debug_zval_dump(demoArray()); 这里 demoArray() 的返回值(没有变量引用 debug_zval_dump 函数里面 demoArray() 调用的结果)所以,这里引用计数变成 2,也就是数组 $aa 和 debug_zval_dump 分别对数组和数组里面的元素进行引用
S.3 -----------------------
代码是这样
echo "\nS.3 -----------------------\n";
unset($aa['a']);
debug_zval_dump(demoArray());
debug_zval_dump($aa);
输出是这样
array(2) refcount(1){
["a"]=>
string(8) "我是 a" refcount(2)
["b"]=>
string(8) "我是 b" refcount(3)
}
array(1) refcount(2){
["b"]=>
string(8) "我是 b" refcount(2)
}
这里是看 unset($aa['a']) 对引用计数的影响
在进行了 unset($aa['a']) 之后
第一组数据,直接输出 debug_zval_dump(demoArray()); 的结果,和 S2 中接近,但是数组中 a 元素的引用变成了 2,也就是说明 unset 有效果了,引用数组中的 a 元素的变量少了一个
第二组数据也就是 $aa 的引用情况,和预想的相同,a 没了,b 不变
---------------------
总结---------------------------------------
1. 上面三组输出,每一组 debug_zval_dump(demoArray()); 的输出结果都是一样的,可以侧面证明,每次 demoArray() 返回的数组,实际上都是独立的一个数组
2. 使用 $aa 变量存储了 demoArray() 返回的数组后,debug_zval_dump(demoArray()); 数组的引用计数器并未增加,证明 $aa 保存的数组和 demoArray() 返回的数组并没有关系
但是数组中元素的引用计数器变化证明,使用 $aa 存储了 demoArray() 返回的数组后,可以认为 $aa 保存数组的元素
3. 使用 unset($aa['a']) 后,数组中元素引用计数器变化,也证明了在这个时候 $aa 和 demoArray() 返回的数组是没关系的
撒花完结~~~~~~
补充下,我不是大神,大家一起交流学习才能提高,因为近期在写 php 的项目,很多经验是在使用其他语言开发的时候带过来的,但是基础概念是相通的,你说的那个参考文档没看过,因为在我用过的语言没有遇到过需要先使用临时变量获取函数结果(当然你说了我懒得去查这是个什么概念是我的锅),再使用结果的情况(我从 PHP 5.6 开始使用,去年升级公司服务器到 PHP7 就更没接触过了),这里涉及到了内存管理的一些知识,如果是 C 可以不用这么复杂的解释,直接打印内存地址就可以了