迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > PHP >

PHP中使用的GC算法

作者:迹忆客 最近更新:2023/02/23 浏览次数:

PHP 使用垃圾收集器 (GC) 来自动管理变量和对象使用的内存。 PHP 使用的 GC 算法是标记清除算法的变体。

标记清除算法的工作原理是将内存分为两部分:“使用中”堆和“空闲”堆。 使用中堆包含程序当前正在使用的所有对象和变量,而空闲堆包含当前未使用的内存。

GC 会定期扫描正在使用的堆,以标记所有仍在被程序使用的对象和变量。 然后它会扫描空闲堆以识别不再使用且可以回收的内存。 GC 将此内存返回给操作系统,使其可用于将来的分配。

PHP 的 GC 算法包括一些额外的功能来优化性能和减少内存碎片。 例如,该算法使用“分代”方法进行 GC,根据对象的年龄将对象分为年轻代和老年代。 新对象放在年轻代,回收频率高,老对象放在老年代,回收频率低。

GC 算法还包括一种“复制”机制,可以在内存区域之间移动对象以减少碎片。 当年轻一代被收集时,幸存的对象被移动到一个新的内存区域,让旧区域完全空闲。 这样可以更容易地在年轻代中分配新对象而不会造成碎片。

以下是 PHP 的 GC 在实践中如何工作的示例:

// 分配一个新对象
$obj = new MyClass();

// 使用对象
$obj->doSomething();

// 将对象设置为 null 以将其标记为垃圾回收
$obj = null;

// GC 将在不再需要时自动回收 $obj 使用的内存

在这个例子中,我们分配了一个 MyClass 类的新对象,并通过调用 doSomething 方法来使用它。 然后我们将该对象设置为 null,这将其标记为垃圾收集。 当GC运行时,它会扫描正在使用的堆,标记所有仍在使用的对象,并扫描空闲堆以识别可以回收的内存。 $obj 使用的内存将返回给操作系统,并可用于将来的分配。

值得注意的是,虽然 PHP 的 GC 算法旨在高效且有效,但它并不完美。 仍有可能发生内存泄漏和碎片的情况,尤其是当我们处理大型或复杂的数据结构时。 了解这些问题并编写代码以尽量减少它们的影响是很重要的。 避免内存泄漏和碎片的一些最佳实践包括:

  • 避免创建大量不必要的对象
  • 使用 unset() 为不再需要的变量释放内存
  • 避免对象之间的循环引用,因为这会阻止 GC 回收内存
  • 使用 PHP 的内置内存分析工具来识别和解决内存问题。

PHP 的 GC 算法使用许多启发式和优化来平衡性能和内存使用。 例如,该算法使用“stop-the-world”方法,这意味着程序在 GC 运行时暂停。 这使得 GC 可以在不受程序干扰的情况下安全地遍历和修改内存。

GC 算法还包括许多可配置的设置,可以调整这些设置以微调其行为。 例如,gc_threshold 设置控制在触发 GC 循环之前允许分配多少内存,而 gc_mem_cushion 设置控制应保留多少额外内存以减少 GC 循环的频率。

这是 PHP 的 GC 算法在实践中如何工作的另一个例子:

// 分配一个包含 10,000 个元素的数组
$data = range(1, 10000);

// 处理数组
foreach ($data as $value) {
  // dosomthing
}

// 将数组设置为 null 以将其标记为垃圾回收
$data = null;

// GC 将在不再需要时自动回收 $data 使用的内存

在此示例中,我们使用 range() 函数分配一个包含 10,000 个元素的数组。 然后我们使用 foreach 循环处理数组并将数组设置为 null 以将其标记为垃圾回收。 当GC运行时,它会扫描正在使用的堆,标记所有仍在使用的对象,并扫描空闲堆以识别可以回收的内存。 $data 使用的内存将返回给操作系统,并可用于将来的分配。


PHP GC 算法核心

PHP 的 GC 算法的核心是一组内存分配和释放函数,用于管理正在使用的堆和空闲堆。 这些函数是用 C 语言实现的,并直接与操作系统的内存管理系统交互来分配和释放内存。

分配变量或对象时,将调用内存分配函数以从操作系统的空闲堆中保留一块内存。 块的大小取决于正在分配的变量或对象的大小,以及 GC 算法所需的任何额外开销。

分配的内存块然后用描述正在存储的对象或变量的元数据标记。 此元数据包括对象的类型、大小和在内存中的位置等信息。

当释放变量或对象时(通过将其设置为 null 或允许其超出范围),将调用内存释放函数以将内存释放回操作系统的空闲堆。 内存释放函数更新与释放的内存块关联的元数据,以将其标记为空闲并可用于将来的分配。

为执行垃圾回收,PHP 的 GC 算法定期扫描正在使用的堆以识别程序仍在使用的对象和变量。 它通过从一组根开始执行此操作,这些根包括当前正在运行的函数中的所有全局变量、函数参数和局部变量。

GC 算法然后递归地遍历所有从根可达的对象和变量。 任何不可访问的对象或变量都被标记为垃圾收集,并释放它们的内存。

PHP 的 GC 算法包括许多额外的优化以提高性能和减少内存碎片。 例如,该算法对 GC 使用“分代”方法,根据对象的年龄将对象分为年轻代和老年代。 这允许 GC 更有效地收集最近分配的更有可能是垃圾的对象。

该算法还包括一种“复制”机制,可以在内存区域之间移动对象以减少碎片。 当年轻一代被收集时,幸存的对象被移动到一个新的内存区域,让旧区域完全空闲。 这样可以更容易地在年轻代中分配新对象而不会造成碎片。

综上所述,PHP 的 GC 算法是使用内存分配和释放函数、元数据结构和递归遍历算法的组合实现的。 该算法旨在高效、有效和可配置,具有许多启发式和优化来平衡性能和内存使用。


代码示例

下面是一个用 PHP 实现的简单标记清除垃圾收集器的示例:

class GC {
  private $objects = array();
  private $root;

  public function setRoot(&$var) {
    $this->root = &$var;
  }

  public function add(&$var) {
    $this->objects[] = &$var;
  }

  public function collect() {
    $marked = array();

    // 标记从根可达的所有对象
    $this->mark($this->root, $marked);

    // 扫描未标记的对象
    foreach ($this->objects as &$object) {
      if (!in_array($object, $marked)) {
        unset($object);
      }
    }
  }

  private function mark(&$var, &$marked) {
    if (!in_array($var, $marked)) {
      $marked[] = &$var;

      if (is_array($var) || is_object($var)) {
        foreach ($var as &$val) {
          $this->mark($val, $marked);
        }
      }
    }
  }
}

此实现定义了一个 GC 类,用于跟踪一组对象和一个根变量。 setRoot() 方法用于设置根变量,而 add() 方法用于将对象添加到集合中。

collect() 方法通过首先使用 mark() 方法标记从根变量可达的所有对象来执行垃圾收集,该方法递归地遍历对象图。 然后 collect() 方法清除所有未标记的对象,释放它们的内存。

以下是此类如何用于管理内存的示例:

$gc = new GC();

// 创建一个对象并将其添加到 GC 的集合中
$obj1 = new stdClass();
$gc->add($obj1);

// 将对象设置为根变量
$gc->setRoot($obj1);

// 创建另一个对象并将其添加到 GC 的集合中
$obj2 = new stdClass();
$gc->add($obj2);

// 取消设置根变量以将其标记为垃圾收集
$obj1 = null;

// 执行垃圾收集
$gc->collect();

在这个例子中,我们创建了两个对象并将它们添加到 GC 对象的集合中。 我们将第一个对象设置为根变量,以确保它和从它可到达的任何对象都将被保留。 然后我们取消设置 root 变量,这将它标记为垃圾收集。 当我们调用 collect() 方法时,GC 将清理第二个对象,因为它不再可以从根变量访问。

需要注意的是 ,这段代码只是一个简单的示例,并不包括 PHP 内置 GC 算法中使用的许多优化和启发式算法。 但是,它提供了标记清除 GC 算法如何工作的基本概念。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

使用 PHP MySQLi 函数获取最后插入的 ID

发布时间:2023/05/09 浏览次数:85 分类:MySQL

本篇文章简要介绍了 PHP mysqli() 函数并演示了如何使用它从 MySQL 数据库中获取最后插入的 ID。它是一个名为 mysqli 的 MySQL 驱动程序扩展版本,

在 PHP 中使用 MongoDB 作为文件存储

发布时间:2023/04/20 浏览次数:133 分类:MongoDB

在为大文件创建可扩展存储方面,MongoDB 及其 GridFS(使用 MongoDB 查询语言 - MQL 编写)是市场上最好的文件存储解决方案之一。 在本教程中,您将学习如何在 PHP 中使用 MongoDB 作为文件存储。

如何在 PHP 中获取时间差的分钟数

发布时间:2023/03/29 浏览次数:183 分类:PHP

本文介绍了如何在 PHP 中获取时间差的分钟数,包括 date_diff()函数和数学公式。它包括 date_diff()函数和数学公式。

PHP 中的重定向

发布时间:2023/03/29 浏览次数:136 分类:PHP

本教程演示了如何将用户从页面重定向到 PHP 中的其他页面

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便