走进php内核】之 垃圾回收(GC)

本文探讨了PHP的垃圾回收(GC)机制,特别是如何处理循环引用问题。当变量通过引用计数无法正常释放时,PHP通过垃圾收集器进行处理。垃圾产生主要涉及数组和对象的循环引用,当变量的引用计数减少后大于0,它们会被放入缓冲区,待缓冲区满后统一进行垃圾检查。检查过程包括遍历缓冲区,减小成员的引用计数,判断是否为垃圾并进行清理。PHP的垃圾收集器可以通过`zend.enable_gc`配置开启,并在内存管理中起着关键作用。
摘要由CSDN通过智能技术生成

1、 垃圾的产生

前面已经介绍过PHP变量的内存管理,即引用计数机制,当变量赋值、传递时并不会直接硬拷贝,而是增加value的引用数,unset、return等释放变量时再减掉引用数,减掉后如果发现refcount变为0则直接释放value,这是变量的基本gc过程,PHP正是通过这个机制实现的自动垃圾回收,但是有一种情况是这个机制无法解决的,从而因变量无法回收导致内存始终得不到释放,这种情况就是循环引用,简单的描述就是变量的内部成员引用了变量自身,比如数组中的某个元素指向了数组,这样数组的引用计数中就有一个来自自身成员,试图释放数组时因为其refcount仍然大于0而得不到释放,而实际上已经没有任何外部引用了,这种变量不可能再被使用,所以PHP引入了另外一个机制用来处理变量循环引用的问题。

下面看一个数组循环引用的例子:

$a = [1];
$a[] = &$a;

unset($a);

unset($a)之前引用关系:

注意这里$a的类型在&操作后已经转为引用,unset($a)之后:

可以看到,unset($a)之后由于数组中有子元素指向$a,所以refcount = 1,此时是无法通过正常的gc机制回收的,但是$a已经已经没有任何外部引用了,所以这种变量就是垃圾,垃圾回收器要处理的就是这种情况,这里明确两个准则:

  1. 如果一个变量value的refcount减少到0, 那么此value可以被释放掉,不属于垃圾
  1. 如果一个变量value的refcount减少之后大于0,那么此zval还不能被释放,此zval可能成为一个垃圾

针对第一个情况GC不会处理,只有第二种情况GC才会将变量收集起来。另外变量是否加入垃圾检查buffer并不是根据zval的类型判断的,而是与前面介绍的是否用到引用计数一样通过zval.u1.type_flag记录的,只有包含IS_TYPE_COLLECTABLE的变量才会被GC收集。

目前垃圾只会出现在array、object两种类型中,数组的情况上面已经介绍了,object的情况则是成员属性引用对象本身导致的,其它类型不会出现这种变量中的成员引用变量自身的情况,所以垃圾回收只会处理这两种类型的变量。

#define IS_TYPE_COLLECTABLE
|     type       | collectable |
+----------------+-------------+
|simple types    |             |
|string          |             |
|interned string |             |
|array           |      Y      |
|immutable array |             |
|object          |      Y      |
|resource        |             |
|reference       |             |

2、 回收过程

如果当变量的refcount减少后大于0,PHP并不会立即进行对这个变量进行垃圾鉴定,而是放入一个缓冲buffer中,等这个buffer满了以后(10000个值)再统一进行处理,加入buffer的是变量zend_value的zend_refcounted_h:

typedef struct _zend_refcounted_h {
    uint32_t         refcount; //记录zend_value的引用数
    union {
        struct {
            zend_uchar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值