搜尋

首頁  >  問答  >  主體

PHP垃圾回收机制

PHP5.2版本的垃圾回收机制主要针对zval结构中的refcount=0时释放变量,但复合类型的数组或对象,环形引用或者引用自己,都是造成内存泄露,PHP官网的介绍5.3的GC机制,通过将zval放入root buffer,进行模拟删除(refcount-1),当refcount==0时被认为是垃圾,而回收,下面是4个步骤:

例如:

<?php
$a = array('one');
$a[] = &$a;
?>

这样$a数组就有两个元素,一个索引为0,值为字符one,另外一个索引为1,为$a自身的引用,内部存储如下:
a: (refcount=2, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=...
)
“...”表示1指向a自身,是一个环形引用:

按照网上表达所说:先放入root buffer中,refcount-1,这时$a的refcount=1,然后unset一下,refcount=0,则认为$a为垃圾
问题:
1. 我现在假设$a数组中,有2个key引用了自己,比如:

<?php
$a = array('one');
$a[] = &$a;
$a[] = &$a;
?>

a: (refcount=3, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=3, is_ref=1)=...
2 => (refcount=3, is_ref=1)=...
)
那么该数组进行unset后肯定是个垃圾,那么比如我先放到buffer, refcount-1,那么refcount=2,然后再unset-1,refcount=1,这样似乎虽然这个数组删除时会造成垃圾,但根据新的GC的机制说,只有当refcount=0时才会被认为是垃圾,那不是矛盾了吗? 那我数组里面是不是只要>=2的key引用了本身,都不会视为垃圾了?

阿神阿神2776 天前690

全部回覆(2)我來回復

  • 高洛峰

    高洛峰2017-04-10 14:56:21

    找到答案了吗?我尝试回答下

    按照楼主说的,看看下面的内容:

    $a = 123;
    $b = $a;   //a: (refcount=2, is_ref=0)=123   b: (refcount=2, is_ref=0)=123
    unset($b);    //a: (refcount=1, is_ref=0)=123

    此时a所指向的zval也会进入垃圾周期,然后对refcount减一,是不是符号a指向的zval也要删除了?显然不是

    这里根据我所了解的说说我的看法:GC不会对可能的垃圾根元素进行减一操作,而是会对根元素下面的元素进行减一操作,这样解释才合理。
    就说说你这种情况,根节点zval计数不会进行减一操作,循环引用的时候,对循环引用指向的zval计数进行减一,这样不管多少循环引用都可以减到0,这样是不是可以说的通了。

    回覆
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-10 14:56:21

    仔细看图你没发现问题么?明明产生了一个自引用,但是为什么refcount还是1呢?应该是变量释放到buffer里面然后refcount--的原因。你就是这块没理解对。

    回覆
    0
  • 取消回覆