php7 垃圾回收机制

是的,平时经常听到大牛说到的gc,就是垃圾回收器,全称Garbage Collection。

早期版本,准确地说是5.3之前(不包括5.3)的垃圾回收机制,是没有专门的垃圾回收器的。只是简单的判断了一下变量的zval的refcount是否为0,是的话就释放否则不释放直至进程结束。

乍一看确实没毛病啊,然而其中隐藏着变量内存溢出的风险:http://bugs.php.net/bug.php?id=33595 ,无法回收的内存造成了内存泄漏,所以PHP5.3出现了专门负责清理垃圾数据、防止内存泄漏的GC。

PHP7中复杂类型的引用计数都维护在各个结构体头部的gc中

gc的作用是什么? 答 对垃圾回收的支持

什么是垃圾回收机制

垃圾回收是一种自动的内存管理机制,当一个变量在程序中不在被需要时(没有任何变量指向这个对象时),应给予以释放,这种内存资源管理称为垃圾回收,这是PHP的 GC 垃圾回收机制,目的是防止内存溢出;

其中一种垃圾回收的方式是使用引用计数,通过对数据存储的物理空间多附加一个计数器空间,当其他数据与相关时,计数器加一,反之相关解除时计数器减一。定期检查各存储对象的计数器,计数器为零的话,则认为对象已经被抛弃而应将其所占物理间回收

引用计数的基本知识
我们要了解GC,那么首先要了解引起垃圾回收的基数是什么。

在php中,每个变量存在一个叫“zval”的变量容器中。一个zval变量容器,除了包含变量的类型和值,还包括另外两个字节的额外信息。第一个是"is_ref"。第二个是"refcount"。

is_ref是一个布尔类型的值,用来标示这个变量是否属于引用集合。通过这个字节,php引擎才能把普通变量和引用变量区分开来,由于php允许用户通过"&"来使用自定义的引用,所以zval中还有一个内部引用计数机制,来进行优化内存。

refcount用来表示这个zval变量容器的变量的个数。所有符号存在一个符号表当中,每个符号都有作用域。

通俗的讲:

  • refcount就是多少个变量是一样的用了相同的值,那么refcount就是这个值
  • is_ref就是当有变量用了&的形式进行赋值,那么is_ref的值就会增加

循环引用问题
在zend_reference结构体的引用计数减1,但仍然大于0,这时候,后面的结可能会成为垃圾,对此不处理可能会造成内存泄露,垃圾收集器会将这部分可能是垃圾的数据收集到缓冲区,同时加入到root环

gc_enabled 是否开启gc
gc_active 垃圾回收算法是否运行
gc_full 垃圾缓冲区是否满了,在debug模式下有用
buf 垃圾缓冲区,php7默认大小为10000个节点位置,第0个位置保留,既不会使用
roots: 指向缓冲区中最新加入的可能是垃圾的元素
unused 指向缓冲区中没有使用的位置,在没有启动垃圾回收算法前,指向空
first_unused 指向缓冲区第一个为未使用的位置。新的元素插入缓冲区后,指向会向后移动一位
last_unused 指向缓冲区最后一个位置
to_free 带释放的列表
next_to_free 下一个待释放的列表
gc_runs 记录gc算法运行的次数,当缓冲区满了,才会运行gc算法
collected 记录gc算法回收的垃圾数

垃圾收集器

  1. 要求数据类型的数组和对象
  2. 没有在缓冲区中存在过
  3. 没有被标记过
  4. 将其gc_info标记为紫色,且记录其在缓冲区的位置
    当缓冲区满了,在收集到新的元素就会触发垃圾回收算法。
    引用计数大于0说明它还在其他地方使用,那么先将元素的引用计数减1,如果发现引用计数为0,则说明任何地方都不再使用它,那么它就是垃圾,需要被回收掉,反之说明不是垃圾,需要将其从回收池移出去

垃圾回收算法

  1. 对roots环中每个元素进行深度优先遍历,将每个元素中gc_info位紫色的标记元素为灰色,且引用计数减1
  2. 扫描roots环中gc_info为灰色元素,如果发现其引用计数仍旧大于0,说明这个元素还在其他地方使用,那么将其颜色重新标记会黑色,并将其引用计数加1(第一步有减1操作)。如果发现其计数为0,则将其标记为白色,该过程同样为深度优先遍历
  3. 扫描roots环,将gc_info颜色为黑色的元素从roots移除,然后对roots中颜色为白色的元素进行深度优先遍历,将其引用计数加1(在第一步有减1操作),然后将roots链表移动到待释放的列表中(to_free)
  4. 释放to_free来列表的元素

在这里插入图片描述

php5.3的

引用计数系统中的同步周期回收,(Concurrent Cycle Collection in Reference Counted Systems) 算法来清除,基本规则是这样的,如果引用计数在+1.说明变量再用,不是垃圾。如果引用技术本身为0,那么是垃圾,需要删除。如果引用计数-1其为非0的时候,将其放到某一区块标记为疑似垃圾,然后队其做很多的模拟操作,最后找到真正的垃圾

通过php.ini 设置修改它的zend.enable_gc

或者通过gc_enable()和gc_disable()

早期版本,准确地说是5.3之前(不包括5.3)的垃圾回收机制,是没有专门的垃圾回收器的。只是简单的判断了一下变量的zval的refcount是否为0,是的话就释放否则不释放直至进程结束。

php中垃圾是如何定义的?

准确地说,判断是否为垃圾,主要看有没有变量名指向变量容器zval,如果没有则认为是垃圾,需要释放。

5.3版本以后php是如何处理垃圾内存的?

判断处理过程
为解决环形引用导致的垃圾,产生了新的GC算法,遵守以下几个基本准则:

1.如果一个zval的refcount增加,那么此zval还在使用,不属于垃圾

2.如果一个zval的refcount减少到0, 那么zval可以被释放掉,不属于垃圾

3.如果一个zval的refcount减少之后大于0,那么此zval还不能被释放,此zval可能成为一个垃圾

are you ok?

来个白话文版:就是对此zval中的每个元素进行一次refcount减1操作,操作完成之后,如果zval的refcount=0,那么这个zval就是一个垃圾

一看就懂系列之 由浅入深聊一聊php的垃圾回收机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟伟哦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值