美文网首页
php gc机制 引用计数 写时复制

php gc机制 引用计数 写时复制

作者: 淡淡de盐 | 来源:发表于2020-09-09 23:31 被阅读0次

简介

如果自己实现一个自动 GC,最简单的方式:在函数定义变量时分配一块内存,用于保存 zval 及对应的 value 结构,在函数返回时将内存释放,如果在函数执行期间该变量作为参数调用了其它函数或赋值给了其它变量,则把变量复制一份,变量间相互独立,不会出现冲突。

这种方式是可行的,内存管理简单,但是带来的问题是:深拷贝效率,而且内存浪费严重,解决问题的方案就是:引用计数 + 写时复制

PS:zval: 变量存在 zval 的变量容器中,除了包含变量的类型和值,还有 is_ref 是 bool 值,用来区分普通变量和引用变量。

引用计数

引用计数用来记录当前有多少 zval 指向同一个 zend_value,有新 zval 指向这个 value,计数加1,相反 zval 销毁时,计数减1,当引用计数为0时,对 value 进行释放。

引用计数记在哪

在 PHP7 中将变量的引用计数保存在了 zend_value。

并不是所有的类型都会用到引用计数。比如 整形、浮点型、布尔型、NULL,它们的值直接通过 zval 保存,因此不会共用 value,而是进行深拷贝。

当然了也有一些类型在特殊情况下也不会用引用计数,这里就不细说了。

写时复制 (copy on write)

写时复制在计算机系统中有着非常广泛的应用。

变量使用了引用计数就会出现其中一个变量修改 value 的情况,这时候要对 value 进行分离,发生修改的变量会复制一份数据出来修改,同断开原来 value 的指向,指向新的 value。

写时复制
PHP7 对象,资源无法进行复制。

循环引用问题

引用计数实现了变量自动 GC 机制,但有一种情况机制无法解决。

$a   = [];
$a[] = &$a;
unset($a);

unset 前,引用计数 refcount = 2,unset($a) 后,减少了一次引用 refcount,此时已经没有任何外部引用了,但是数组中仍然有一元素指向引用。

因变量无法回收导致内存始终得不到释放,造成内存泄漏,这种情况就是循环引用。

为了解决这种无法释放的变量垃圾,PHP 引入了另外一种机制 垃圾回收

垃圾回收

怎么知道变量是垃圾呢?
  1. 如果一个变量 value 的 refcount 减少到0,那么此 value 可以被释放,不属于垃圾
  2. 如果一个变量 value 的 refcount 减少后大于0,那么此 value 还不能被释放,此 value 可能 成为一个垃圾

第一种情况垃圾回收器不会处理

只有第二种情况垃圾回收器会把可能成为垃圾的 value 收集起来,保存到一个 buffer 缓存区中。等达到一定数量后启动垃圾鉴定程序,真正的垃圾释放。

既然是把垃圾收集起来,那就要有算法做回收 回收算法

回收算法

垃圾回收池中,gc_root_buffer 它是一个双向链表,同时记录引用计数相关信息,zend_gc_globals 维护着 gc 的整信息,里有很多信息就不细说了!

三色标记

  • 紫色 称为疑似垃圾
  • 黑色:对象正在被使用
  • 灰色:可能被回收
  • 白色:对象垃圾
简单描述垃圾鉴定过程
  • 步骤1: 遍历垃圾回收器的 buffer 缓存区,把当前 value 标记为灰色,然后对当前 value 的成员进行深度优先遍历,成员 refcount 减 1,并标记为灰色。
  • 步骤2: 重复遍历 buffer,检查当前 value 引用是否为 0,为 0 则表示为垃圾,则标记为白色,如果不为 0 则排除引用全部来与自身成员的可能,表示还有外部引用,并不是垃圾。这时候因为步骤1 对成员进行了 refcount 减1 操作,需要在还回去,再对所有成员深度遍历,把成员 refcount 加1,同时标记为黑色。
  • 步骤3: 再次遍历 buffer 将非 白色节点从 buffer 中删除,最终 buffer 缓存区中全部为真正的垃圾,最后将这些垃圾释放,回收完成。
垃圾回收算法流转图

其实说了这么多,就是为了筛选对象是否有自身引用,遍历对象所有成员对其 refcount 减1。遍历完如果 refcount 为0,说明有自身引用,则为垃圾。
那些不是自身引用或有外部引用的,从 buffer 中删除。
最后 buffer 中只留下了真正的垃圾,对其释放内存。

相关文章

  • php gc机制 引用计数 写时复制

    简介 如果自己实现一个自动 GC,最简单的方式:在函数定义变量时分配一块内存,用于保存 zval 及对应的 val...

  • python垃圾回收机制

    目录 一、引用计数机制1、引用计数机制优点2、引用计数机制缺点 二、Garbage collection(GC)1...

  • php 内存回收机制

    php5.3版本以后的才有了所谓的新的垃圾回收机制GC,以前是基于引用计数的方式,这里就需要提一下引用计数的知识,...

  • php7的写时复制机制

    1. 什么是写时复制 在《php7引用计数》的文章中,我们知道,对于复制类型的变量,在赋值时,我们并没有重新复制一...

  • chapter-4 GC算法与种类

    GC 算法与种类 ■ GC的概念■ GC算法• 引用计数法• 标记清除• 标记压缩• 复制算法■可触及性■ Sto...

  • golang的gc流程

    一 经典的GC算法 引用计数(reference counting) 标记-清扫(mark & sweep) 复制...

  • JVM GC

    GC 概念 GC分类 引用计数法 可到达分析 GC内存回收算法 复制 标记清理 标记整理 参考文章 咱们从头到尾说...

  • PHP垃圾回收机制

    垃圾的产生 之前的文章已经介绍过PHP的引用计数机制-PHP内核探索之变量-理解引用,当变量赋值、传递时并不会直接...

  • python 垃圾回收机制(GC)

    python 中的垃圾回收机制 Python的GC模块主要运用了“引用计数”(reference counting...

  • Python 面试题

    1. Python垃圾回收机制 Python GC主要使用引用计数(reference counting)来跟踪和...

网友评论

      本文标题:php gc机制 引用计数 写时复制

      本文链接:https://www.haomeiwen.com/subject/edxmrktx.html