php的gc是弥补引用计数缺陷的辅助回收机制,通过根缓冲区登记疑似循环对象,再以三色标记法识别并释放真正不可达的循环引用垃圾。

PHP 的 GC 循环引用检测,本质是为弥补引用计数机制的天然缺陷而设计的一套辅助回收系统。它不替代引用计数,而是与之协同:引用计数负责日常即时释放,GC 负责揪出那些“refcount > 0 却实际已无人可达”的对象闭环。
循环引用为什么会导致内存泄漏
当对象 A 持有对 B 的引用,B 又持有对 A 的引用,即使外部所有变量都 unset,A 和 B 的 refcount 仍为 1 —— 引用计数机制判定它们“还在被使用”,于是内存永不释放。
- 这类对象无法通过 refcount=0 触发释放,但又确实不再被脚本逻辑访问,属于“逻辑垃圾”
- PHP 不会主动遍历全部变量判断可达性(开销太大),所以需要一种轻量级候选机制
根缓冲区:GC 的“可疑人员名单”
每次一个变量被 unset 或作用域结束,若其 refcount 减后仍大于 0,且该变量是容器类型(如对象、数组),PHP 就把它加入根缓冲区——不是立刻分析,而是先登记在册。
- 默认容量为 10,000 条,当缓冲区填充到约 5,000 条时,自动触发 GC 扫描
- 这个缓冲区是双向链表结构,插入和清空效率高,避免频繁扫描全量内存
- 它只收“可能循环”的对象,过滤掉简单标量、字符串等无需 GC 处理的类型
三色标记法:高效识别真正不可达的对象
GC 启动后,并非暴力清空整个缓冲区,而是执行一套可控的图遍历算法:
- 初始将所有缓冲区对象标记为“白色”(待定)
- 从中选若干作为“灰色”,表示“已入队、待检查其引用”
- 遍历每个灰色对象的所有成员变量,把其所指向的其他对象也标灰;处理完后自身标“黑色”(确认存活)
- 最终仍为白色的对象,说明从任何根路径都不可达 → 真正的循环垃圾,立即释放
触发与调优:什么时候跑、怎么让它更稳
GC 不是定时任务,而是按需响应。除了缓冲区阈值,还有三种常见触发时机:
- 手动调用 gc_collect_cycles(),适合长生命周期脚本(如 Swoole Worker)中关键节点清理
- 请求结束前自动运行一次(FPM 场景下影响小,常驻进程必须关注)
- 内存接近 zend.memory_limit 时,引擎可能提前介入回收
若发现 GC 频繁导致毛刺,可适当增大 gc.root_buffer_size(如设为 20000),减少触发次数;但不宜关闭 GC,否则循环引用会持续累积内存。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











