本文目录导读:

PHP的垃圾回收(Garbage Collection,GC)机制主要针对Zend引擎的内存管理,它通过引用计数(Reference Counting)和周期自动检测(Cycle Collecting)两种方式协同工作,以下是其核心运作原理:
基础内存管理 – 引用计数
PHP变量存在一个zval结构中,每个zval包含一个refcount(引用计数)字段。
- 赋值:当变量被赋值给另一个变量时,
refcount加1。 - 函数调用:将变量作为参数传递时,新创建的变量会共享同一个
zval,引用计数增加。 - 销毁:当变量离开作用域(如函数结束、
unset())时,引用计数减1。 - 回收:当
refcount降至0时,Zend引擎立即回收该变量占用的内存。
例子:
$a = new stdClass(); // refcount = 1 $b = $a; // refcount = 2 unset($a); // refcount = 1 unset($b); // refcount = 0 → 立即回收
循环引用问题 – 周期检测
引用计数无法处理循环引用,当两个或多个对象相互引用时,引用计数永远不会降为0,导致内存泄漏。
class Node {
public $child;
}
$a = new Node();
$b = new Node();
$a->child = $b; // $b的refcount = 2(自身+$a->child)
$b->child = $a; // $a的refcount = 2
unset($a); // $a的refcount变为1,$b的refcount仍为2
unset($b); // $b的refcount变为1,$a的refcount仍为1
// 两个对象的refcount均>0,不会被引用计数回收
周期垃圾回收器(Cycle Collector)
PHP引入了一个专门的周期垃圾回收器来解决此问题,其核心是可能垃圾根缓冲区,运作分为几个阶段:
a)标记可疑根
当变量的refcount减少到一个非0值(即减少但没有归零)时,该变量会被加入可能垃圾根缓冲区,因为这种情况表明可能存在循环引用。
b)GC触发
- 主动触发:通过调用
gc_collect_cycles()手动启动。 - 自动触发:当缓冲区中的可疑根数量达到阈值(默认10000)时,GC自动运行。
- PHP 7.3+引入了增量GC(默认关闭),可以在请求中分步执行,避免长时间卡顿。
c)收集与清除
- 计算有效引用数:GC遍历所有可疑根,暂时减少每个节点的引用计数(记为
depth),并递归遍历所有子节点。 - 判断是否为垃圾:如果某个节点的
depth减为0(表示只有循环引用自身),则标记为垃圾。 - 释放:删除被标记为垃圾的节点及其循环引用链。
简化流程:
- 缓冲区装满(或手动触发)→ 遍历所有可疑根,模拟删除自身引用 → 若引用变为0,则为垃圾 → 真正释放。
PHP版本差异与优化
| 版本 | 关键变化 |
|---|---|
| PHP 5.3 | 引入周期回收器(默认开启) |
| PHP 7.0 | 引入改进的zval结构,引用计数更轻量 |
| PHP 7.3 | 增加增量GC(zend.enable_gc=0可关闭,增量模式需zend.gc_incremental) |
| PHP 8.0+ | 进一步优化内存布局,GC性能提升 |
如何观察与调优
- 查看当前垃圾:
gc_status()(PHP 8.1+)或gc_collect_cycles()的返回值。 - 关闭GC(不推荐):在
php.ini设置zend.enable_gc = Off。 - 触发阈值调整:
gc_enabled()返回当前状态,不可直接改阈值,但可通过代码控制,如在大量循环引用操作后手动gc_collect_cycles()。 - 减少循环引用:使用弱引用(
WeakReference,PHP 7.4+)或手动解除环形依赖。
PHP的GC = 引用计数(立即回收) + 周期回收器(清理循环引用),前者处理常规泄漏,后者在处理复杂对象图时额外启动,确保没有无用的循环结构长期占用内存,理解GC有助于处理长周期CLI脚本、高并发服务中的内存泄漏问题。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播