PHP-php引用计数问题

发布于 2016-10-28 09:06:35 字数 273 浏览 1189 评论 1

<?
$a = array( 'one' );
$a[] =& $a;
xdebug_debug_zval( 'a' );
echo '<pre>';
debug_zval_dump($a);
echo '</pre>';
unset($a);
xdebug_debug_zval('a');
debug_zval_dump($a);
?>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

瑾兮 2016-12-02 20:37:46

首先说一下,xdebug_debug_zval() 出来的结果是正确的,但是也不能说 debug_zval_dump()的结果是错误的,你上边代码 refcount(1)也是正确的,原因很简单
在函数传递参数时有引用计数增加操作,举个例子:

1) $a = 'a';
2) $b = &$a;
3) $c = $a;
4) debug_zval_dump($a); // string(1) "a" refcount(1)

在 第1行 时 符号 a 指定 的zval容器 refcount 为 1

在 第2行 时 符号 a 指定 的zval容器 refcount 为 2,is_ref 为 1 (仅表示真或者假) 符号 b 与 a 指向 相同的zval容器.

在 第3行 时 由于 a,b 指定的是一个容器,而 $c = $a 也没有使用 & 符,所以 这里的 符号c 分配出一个新的容器,类型,与值 同 a,b指向的容器。 是新分配出来的,所以 符号 a 指向的 zval容器 的refcount 值没有增加。我感觉这里没必要说为什么会分配出新的容器了,试想一下,如果也是指定同一个容器的话,改边 c 的值,那么 a,b 也会受到影响,这样就乱套了。

在 第 4 行 ,由于 函数传递参数也会是引用增加,所以 这里 可以理解为 $d = $a , 所以和第3行的情况一样,a 指向 的 zval 的 refcount 值也没有增加。

那么根据这四行可以看出 现在 符号a指向的zval容器的refcount 为 2 ,is_ref 为 1 , 但是debug_zval_dump()函数打印出的为什么是 string(1) "a" refcount(1) ? 因为 debug_zval_dump() 函数只输出了 php 内部实现的引用计数机制,如果程序中使用 & 取地址符 不被算在内,同样它也没有输出is_ref 的值(is_ref 表示该容器是否被引用), 所以 输出 refcount(1) .
所以现在也可以理解 xdebug_debug_zval(); 的参数为什么是字符串了吧,调用的时候引用计数不会增加。

关于你第二个疑问:

如果是2个引用的话 unset之后减一 应该还有值啊?

其实你说的没错,是还有值,而且也正如你说的unset之后 refcount -1 之后 refcount 值还为 1 ,当一个 容器 的refcount 为 0 的时候 才会在内存中销毁。像你给出的例子,unset 之后只是 将 符号 a 销毁了,也就是说没有符号执行这个zval容器了,而 这块内存并没有释放出来,这就照成了内存泄露,只有进程结束后,才可以释放内存。

举个简单的例子测试下:

echo memory_get_usage(),"n"; //2
$a = range(1,10000); //3
$a[10000] = &$a; //4
echo memory_get_usage(),"n"; //5
unset($a); //6
echo memory_get_usage(),"n"; //7

输出为:
133696
919672
919672

xdebug 跟踪的结果为:

0.0016 129704 +129704 -> {main}()test.php:0
0.0017 133696 +3992 -> memory_get_usage() test.php:2
0.0018 133744 +48 -> range()test.php:3
0.0039 919672 +785928 -> memory_get_usage() test.php:5
0.0040 919672 +0 -> memory_get_usage() test.php:7
0.0068 882800

将第 4 行 代码 改为:$b = &$a;
结果为:
133784
919760
919760
根据这两段代码的的结果很明显看出,内存没有被释放。修改第 4行,只想说明之前的情况和现在修改后的情况是一样的。

如果在第 6 行代码前 增加: unset($a[10000]);
结果为:
133912
919888
198312

xdebug 跟踪的结果为:

0.0015 129896 +129896 -> {main}() D:wampwwwtest.php:0
0.0015 133912 +4016 -> memory_get_usage()test.php:2
0.0016 133960 +48 -> range() test.php:3
0.0043 919888 +785928 -> memory_get_usage() test.php:5
0.0059 198312 -721576 -> memory_get_usage() test.php:8
0.0191 142216

忽略掉函数本身占用的内存,那么可以很明显看出 将内存释放了。

其实像你给出的这个例子使用 $a = null,的方式是最好不过了,因为 引用$a的变量也为 null了。

以上都是个人总结,可能有说的不对的地方,还请大家指出。。。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文