php 7.3 的垃圾回收机制仅清理循环引用导致的不可达 zval 内存,不处理 redis、apcu、opcache 等应用层缓存;需手动调用 gc_collect_cycles() 触发周期回收,或提前置 null 破环。

PHP 7.3 的垃圾回收(GC)机制本身**不负责清理应用层缓存**(如 Redis、APCu、文件缓存等),它只管理 PHP 自身运行时的内存——特别是 zval 结构中因变量、数组、对象等产生的内存占用。所谓“清理缓存”,在 GC 上下文中实际是指**触发垃圾回收以释放被循环引用长期占据却已不可达的内存**。
理解 GC 清理的是什么
PHP 7.3 沿用并优化了自 PHP 5.3 引入的混合回收机制:
- 引用计数(refcount):对每个可计数类型(array、object、string 等)维护一个计数器;当 refcount 降为 0,内存立即释放
- 周期检测(cycle collection):专门处理循环引用(如对象 A→B→A),这类结构 refcount 永远 > 0,必须靠 GC 周期识别并批量清除
- GC 不清理 opcode 缓存(OPcache)、不清理 APCu 用户缓存、不清理外部存储——这些需手动调用
opcache_reset()或apcu_clear_cache()
手动触发 GC 清理循环引用内存
在常驻进程(如 Swoole、PHP-FPM 长连接、CLI 循环任务)中,GC 不会自动高频运行,默认阈值为 10000 个待检节点。若你观察到内存缓慢增长且 unset() 后不下降,大概率是循环引用未被及时回收:
- 调用
gc_collect_cycles()可强制执行一次完整 GC 周期,返回本次清理的 zval 个数(>0 表示有垃圾被回收) - 建议在关键逻辑结束、大循环迭代末尾或内存敏感操作后主动调用:
if (gc_enabled()) { gc_collect_cycles(); } - 避免高频调用(如每毫秒一次),它有开销;合理间隔可设为每处理 100–1000 条数据后执行一次
辅助诊断与优化步骤
确认是否真需 GC 干预,而非其他内存问题:
- 用
memory_get_usage(true)和gc_status()查看当前内存分配与 GC 状态(如roots数量、collected历史) - 用
xdebug_debug_zval()(需 Xdebug)检查可疑变量的refcount和is_ref,判断是否陷入循环 - 提前破环比依赖 GC 更可靠:销毁前将循环引用字段置为
null,例如$obj->parent = null;,让 refcount 能自然归零 - 确认
zend.enable_gc = On(默认开启),禁用后 GC 完全不工作
不是 GC 责任但常被混淆的“缓存”
以下情况与 PHP 垃圾回收无关,需单独处理:
-
OPcache 编译缓存:调用
opcache_reset()或重启 Web 服务器 -
APCu 用户缓存:用
apcu_clear_cache('user')或按 key 删除 -
全局变量/静态属性累积:这是设计问题,应改用局部作用域或显式重置,GC 不会帮你清空
static $cache = []; -
资源未关闭(cURL、PDO、文件句柄):这些不走 refcount 流程,需手动
curl_close()、$pdo = null;等
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











