垃圾回收机制

垃圾回收机制是一种动态存储分配方案。它会自动释放程序不再需要的已分配的内存块。 自动回收内存的过程叫垃圾收集。垃圾回收机制可以让程序员不必过分关心程序内存分配,从而将更多的精力投入到业务逻辑。 在现在的流行各种语言当中,垃圾回收机制是新一代语言所共有的特征。

垃圾的产生

PHP7 中复杂类型,像字符串、数组、对象等的数据结构中,头部都有一个 gc, 这个 gc 的作用就是用来对垃圾回收的支持。当变量赋值、传递时,会增加 value 的引用数, unset、return 等释放变量时再减掉引用数,减掉后如果发现 refcount 变为 0 则直接释放 value,这是变量的基本回收过程。

不过有一种问题是这个机制无法解决的,就是循环引用的问题。

什么是循环引用呢? 简单说就是变量的内部里存的 value 又引用了变量自身。 这种比较经常发生在数组和对象类型的变量上。

这里先讲一下引用,即 zend_reference 这个类型,这个是 PHP7 新增的变量类型,当对变量使用 “&” 操作时,会创建新的中间结构体 zend_reference,这个结构体会真正的指向对应的 value 结构。

举个例子:// 当进行如下赋值操作时

$a = 'hello'; // $a -> zend_string

$b = $a; // $b,$a -> zend_string

$c = &$b; // $c,$b -> zval(type = IS_REFERENCE, refcount = 2) -> zend_string

最终会变成如下这样:

即 $b 和 $c 的 zval 是通过中间结构体 zend_reference 再指向最终的 zend_string。

回到循环引用的问题,举个数组循环引用例子:$a = [1];

$a[] = &$a;

unset($a);

使用 & 操作之后,变量 a 就变成了引用类型且引用计数 refcount 为 2,而又赋值给自己里面的元素,即变量 a 变成了自己引用自己。

具体如下如所示:

当 unset 之后就变成下图这样:

即 $a 所在的 zval 类型已经变成了 IS_UNDEF 了,zend_reference 结构体的引用计数减 1,但是仍然大于 0,这时候,这部分结构体就变成了垃圾,对此不处理的话,就可能会造成内存泄露。这里就需要垃圾收集器将这部分收集到缓冲区,之后进行回收处理。

回收过程

如果当变量的 refcount 减小后大于 0,PHP 并不会立即对这个变量进行垃圾鉴定和回收,而是放入一个缓冲区中,等这个缓冲区满了以后 (10000 个值) 再统一进行处理,加入缓冲区的是变量 zend_value 里的 gc,目前垃圾只会出现在数组和对象两种类型中,数组的情况上面已经介绍了,对象的情况则是成员属性引用对象本身导致的,其它类型不会出现这种变量中的成员引用变量自身的情况,所以垃圾回收只会处理这两种类型的变量。

gc 的结构 zend_refcounted_h 具体如下:typedef struct _zend_refcounted_h {

uint32_t refcount; // 记录 zend_value 的引用数

union {

struct {

zend_uchar type, // zend_value的类型, 与zval.u1.type一致

zend_uchar flags,

uint16_t gc_info // GC信息,记录在 gc 池中的位置和颜色,垃圾回收的过程会用到

} v;

uint32_t type_info;

} u;

} zend_refcounted_h;

一个变量只能加入一次缓冲区,为了防止重复加入,变量加入后会把 zend_refcounted_h.gc_info 置为 GC_PURPLE,即标为紫色,后续不会重复插入。

垃圾缓冲区是一个双向链表,等到缓存区满了以后则启动垃圾检查过程:遍历缓冲区,对当前变量的所有成员进行遍历,然后把成员的 refcount 减 1 (如果成员还包含子成员则也进行递归遍历,即深度优先遍历),最后再检查当前变量的引用,如果减为了 0 则为垃圾。这个算法的原理核心是:垃圾是由于成员引用自身导致的,那么就对所有的成员减一遍引用,如果发现最后变量本身的 refcount 变为了 0 则就表明其引用全部来自自身成员,即其他任何地方都不再使用它,那么它就是垃圾,需要被回收掉。反之说明不是垃圾,需要将其从缓冲区移出去。具体的过程如下:

(1) 从缓冲区链表的 roots 开始遍历,把当前 value 标为灰色 (zend_refcounted_h.gc_info 置为 GC_GREY),然后对当前 value 的成员进行深度优先遍历,把成员 value 的 refcount 减 1,并且也标为灰色;

(2) 重复遍历缓冲区链表,检查当前 value 引用是否为 0,为 0 则表示确实是垃圾,把它标为白色 (GC_WHITE),如果不为 0 则排除了引用全部来自自身成员的可能,表示还有外部的引用,并不是垃圾,这时候因为步骤 (1) 对成员进行了 refcount 减 1 操作,需要再还原回去,对所有成员进行深度遍历,把成员 refcount 加 1,同时标为黑色;

(3) 再次遍历缓冲区链表,将非 GC_WHITE 的节点从 roots 链表中移出,最终 roots 链表中全部为真正的垃圾,最后将这些垃圾清除。

推荐教程:《PHP7》《PHP教程》

php7垃圾回收机制l_PHP7 垃圾回收机制(GC)解析相关推荐

  1. python 内存回收机制_Python垃圾回收机制是什么

    不同于C/C++,像Python这样的语言是不需要程序员写代码来管理内存的,它的GC(Garbage Collection)机制 实现了自动内存管理.GC做的事情就是解放程序员的双手,找出内存中不用的 ...

  2. java垃圾回收机制_乐字节Java|GC垃圾回收机制、package和import语句

    本文接上一篇:乐字节Java|this关键字.static关键字.block块.本文是接着讲述JavaGC垃圾回收机制.package 和 import语句. 一.GC垃圾回收机制 GC全名:Garb ...

  3. java垃圾回收菜鸟_java垃圾回收机制

    1:对象可能不被垃圾回收 2:垃圾回收并不等于"析构" 3:垃圾回收只与内存有关,为了回收程序不再使用的内存 java虚拟机采用了"自适应"的垃圾回收机制,即& ...

  4. JVM内存管理机制和垃圾回收机制

    JVM内存管理机制和垃圾回收机制 JVM结构 图片描述: java源码编译成class文件 class文件通过类加载器加载到内存 其中方法区存放的是运行时的常量.静态变量.类信息等,被所有线程共享 堆 ...

  5. JVM初学之JVM的垃圾回收机制与垃圾回收器

    如何判断对象是否"已死": 首先,我们要对对象进行垃圾回收之前,就必须要判断对象是否"已死",也就是是否可回收.这里有两种判断逻辑: 引用计数法: 在对象内部维 ...

  6. 4.1 心跳机制和垃圾回收机制

    任务目的 了解心跳机制流程 知晓 NameNode 感知 DataNode 掉线死亡的时长计算公式 学会在配置文件中设置心跳机制 掌握开启 HDFS 垃圾回收机制的方法 任务清单 任务1:Hadoop ...

  7. JVM (二) 垃圾回收机制概念+垃圾回收器种类

    前言 做一个有趣的程序员.哈哈哈哈 本次铁村的小蓝猫主要给大家详细分享JVM中垃圾回收机制 学习JVM 肯定是要了解垃圾回收机制的. 分享前,我们先了解下本次分享内容的框架. 一.垃圾回收机制定义 1 ...

  8. JVM3--垃圾回收机制:垃圾回收概述、垃圾回收算法及分类

    一.垃圾回收概述 1.垃圾对象:运行程序中没有任何指针指向的对象 2.垃圾回收区域: 方法区+堆空间        频繁回收Young区        较少回收old区        基本不动Perm ...

  9. JVM分代回收机制和垃圾回收算法

    JVM系列文章目录 初识JVM 深入理解JVM内存区域 玩转JVM对象和引用 JVM分代回收机制和垃圾回收算法 细谈JVM垃圾回收与部分底层实现 Class文件结构及深入字节码指令 玩转类加载和类加载 ...

最新文章

  1. mybatis深入理解(一)之 # 与 $ 区别以及 sql 预编译
  2. mac book pro怎么安装python_Mac安装python细节
  3. 5.贝叶斯算法、单词拼写错误案例
  4. 关于游戏烂代码的那些事(下)
  5. ubuntu系统操作常见错误
  6. 每一个正整数可以表示为3个三角形数之和
  7. 微擎支付返回商户单号_一步一步教你在SpringBoot中集成微信扫码支付
  8. 纯 js 导出 excel
  9. Web前端技术历经的洗礼和蜕变
  10. VC.NET字符指针与String的转换
  11. 吃下去的东西老是往上翻上来_食管裂孔疝的这个诱因你知道吗?医生:不要再吃过烫的食物...
  12. python elif可以单独使用_Celery在python中的单独使用
  13. 两款在线小游戏-e梦迷宫、恐龙跳一跳
  14. 实战分享丨MySQL 与Django版本匹配相关经验
  15. wxpython textctrl绑键盘事件_wxPython控件学习之TextCtrl(三)响应文本控件事件
  16. FDR错误发现率-P值校正学习
  17. HTML5语义元素的使用
  18. Language Understanding for TextGames using Deep Reinforcement
  19. 字符串匹配(KMP)算法及Java实现
  20. i310100和i59400f哪个好 i3 10100和i5 9400f差距大吗

热门文章

  1. IDEA for Mac 常用快捷键
  2. zookeeper和Kafka的关系
  3. win10如何截屏_win10系统电脑截屏的多种操作方法
  4. java基础-02数据类型
  5. C++——override
  6. 没有桌面体验功能就不能进行图片打印
  7. Linux下第一次使用MySQL数据库,设置密码
  8. centos7新机器需要安装的。。。。。。
  9. Mac 快速修改 hosts 文件
  10. vs2010 代码混淆 代码加密