垃圾收集器(GC)是 PHP 中的内部内存管理系统,但有一些微妙之处需要理解。
GC 自动化内存管理,消除了通过手动任务处理内存的麻烦(这会很乏味)。
这使得开发人员可以专注于他们的业务逻辑,而不必过度担心“内存不足”错误。
当然,这不是魔法。
释放不再需要的对象可以防止内存泄漏。
GC 使用计数机制来确定要丢弃的元素。如果没有引用指向特定对象(即 $counter = 0),则该对象有资格进行清理。
它工作得很好,但一些引用可能有问题:
class A { public $b; } class B { public $a; } $a = new A(); $b = new B(); $a->b = $b; $b->a = $a; unset($a); unset($b);
在这种设计不佳的情况下,即使我们取消设置 $a 和 $b,PHP 也不会释放内存,因为它们相互引用,导致 PHP 认为它们仍在使用中。
幸运的是,还有另一种称为循环收集器的机制:
gc_collect_cycles();
粗略地说,收集器会遍历所有引用并应用一种算法来标记正在使用的对象,从而显示要收集的对象(未标记的对象)。
但是,PHP 不会触发自动循环收集,直到达到具有潜在循环引用的 10,000 个对象 的阈值。
再次强调,这不是魔法,因此只有在少数情况下才必须调用 gc_collect_cycles()。
糟糕的设计可能会导致对象之间的关系过于复杂,从而导致更多的引用和更频繁的垃圾回收。
每个引用计数对象都需要额外的存储空间来存储其引用计数。
来源:维基百科 - 引用计数
与内存清理操作相关的开销会显着影响全局性能,并最终增加特定场景中的执行时间。
10 年前,Composer 仅通过使用 gc_disable() 函数就获得了巨大的性能提升。
来源:Composer - 禁用 GC
确实,PHP 7 极大地改进了 GC,所以现在已经不是 2014 年的样子了。
此外,PHP 8 版本改进了内存分配策略,并添加了更多有关 GC 操作的有用统计信息,以便更好地监控(8.3 中的 gc_status())。
大多数PHP应用程序都是请求驱动的,请求结束时内存会自动清除。
再说一遍,这很酷,但并不神奇。异步请求和长期存在的对象/守护进程会发生什么?
您可能会在某些时候遇到内存泄漏。
此时,你可能还看不出 PHP 的 GC 与其他语言有何不同。
大多数时候,其他语言不依赖引用计数来收集垃圾,或者可能使用不同的实现。
例如,许多使用跟踪算法,该算法也标记未使用的对象,但不会增量操作。这是一个图的遍历。
此外,某些语言不允许这种直接控制(例如,运行时开/关)。
像往常一样,有一些优点和不方便,所以你可能会看到一些混合方法。
您可以利用内置的 gc_* 帮助程序。
例如:
这些函数有助于调试或微调垃圾收集必要时。
您可以阅读这篇文章以获取更多见解:
PHP 7.4 引入了弱引用,PHP 8 引入了弱映射。
弱映射可以被描述为弱引用的集合。
此数据结构是一种多功能键值存储,可帮助 PHP 跟踪项目,而不会造成混乱或消耗过多空间。
您可能会将其视为临时存储,当不再需要时将立即清除,因为没有[强]引用可以阻止垃圾收集:
class A { public $b; } class B { public $a; } $a = new A(); $b = new B(); $a->b = $b; $b->a = $a; unset($a); unset($b);
对于大多数用法,您不必担心内存管理,因为 PHP 已经处理了它。
但是,由于现代堆栈使用长寿命对象,因此您需要监视应用程序是否存在潜在的内存泄漏。
如果遇到问题,您可能需要优化代码和/或直接与 GC 交互。
以上是PHP:用简单的话解释垃圾收集器的详细内容。更多信息请关注PHP中文网其他相关文章!