3
回答
PHP垃圾回收机制的问题,有关复合变量的回收。
华为云4核8G,高性能云服务器,免费试用   

在PHP官网和很多博客中可以看到很多人在对PHP垃圾回收机制在进行解释。

对于入门不久的我来说,有很多地方着实看不懂,其中一点是:

在复合变量,如数组的回收的时候,假设数组里面有两个元素,如下代码:

<?php
$a = array( 'meaning' => 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );
?>

以上例程的输出类似于:

a: (refcount=1, is_ref=0)=array (
   'meaning' => (refcount=1, is_ref=0)='life',
   'number' => (refcount=1, is_ref=0)=42
)

意思就是说,PHP会创建三个zval变量容器,那当我们unset($a)的时候,是不应该一下子清除三个zval变量容器呢?

<?php
$a = array( 'meaning' => 'life', 'number' => 42 );

unset($a);
@var_dump($a);

@var_dump($a['meaning']);

@var_dump($a['number']);
?>

这一串代码什么都不会输出,因为获取不到任何的值

也就是说,我们unset($a)的同时,php也应该自动执行了代码中没有的unset($a['meaning'])和unset($a['number']);如果不是的话,那岂不是只要unset一个数组就会造成内存泄漏?

按照上面这种思路来看下面的例子:

<?php
$a = array( 'one');

$a[] = &$a;

xdebug_debug_zval( 'a' );
?>

以上例程的输出类似于:

a: (refcount=2, is_ref=1)=array (
   0 => (refcount=1, is_ref=0)='one',
   1 => (refcount=2, is_ref=1)=...
)

图示:

自引用(curcular reference,自己是自己的一个元素)的数组的zval

之后官方网站和各个博客上说:这个时候unset($a)就会造成内存泄漏。

我的疑惑是,按照上面的思路,unset一个数组的时候应该也会同时unset它内部的元素,那同理,这里unset($a)的时候,应该也是会unset($a[1])的吧,那这样为什么还会造成内存泄漏。

初入门,很多不懂,希望有大牛可以给解答一下疑惑。

PHP
举报
你六六六
发帖于1周前 3回/484阅
共有3个答案 最后回答: 6天前

php7中应该不会造成内存泄漏。array本质上是一个hashtable,当unset的时候,会被当成hashtable来处理,肯定不会导致内存泄漏。

说会造成内存泄漏的是在PHP5版本,在PHP7版本重写了垃圾回收机制了。

看你的例子,php也是通过引用计数来管理内存的,所以unset并不会直接释放内存,它只是把引用减1,当这个引用数为0时才会释放内存。最后一个例子为什么会有内存泄漏,是因为你在$a数入加入了$a自己的引用,变成循环引用,这样unset($a)时,引用数减1,但数组内存还有一个引用,所以就得不到释放。然而,php的传统方式,运行后进程就被销毁(不是长驻内存),所有内存就回收,所以研究这个有什么意义?

--- 共有 1 条评论 ---
你六六六因为公司用了swool来加速框架,提升性能,也就是做的常住内存,所以说,要让我们平时写代码要注意一些点,所以会看这一块的知识。 关于这个问题,就说计数上面,第一个例子,应该也是两个元素也需要计数减一把,那么最后一个例子,虽然是循环引用,但是总引用数是2,$a计数-1之后,其内部的元素不是也应该分别对应的-1吗?那么循环引用的那个元素也应该-1,这样,那个refcount不就是减了两次,最后也就是0 5天前 回复
顶部