weakreference 和 weakmap 用于避免对象被意外强引用而阻碍 gc 回收。weakreference 允许安全持有对象而不增加引用计数,适用于事件监听、闭包捕获等场景;weakmap 则以对象为键自动清理元数据,适合缓存、监听器注册等。

长驻进程里对象不释放,不是 GC 失灵,而是你无意中“拽住了它”。WeakReference 和 WeakMap 的作用,就是让你松手——既保功能,又不挡回收。
什么时候必须用 WeakReference
当一个对象需要被其他地方临时访问,但又不该因此“活下来”时。典型场景包括:
- 事件监听器回调里引用了某个服务实例,而该监听器注册在全局调度器中长期存在
- 闭包捕获了
$this,而$this又持有了容器或大量依赖 - 缓存键是对象本身(比如用
User实例作数组 key),导致对象无法被回收 - 协程或定时任务中持有大对象,任务结束却没清理上下文
WeakReference:给对象装个“可断连”的钩子
它不增加引用计数,对象一旦失去所有强引用,立刻能被 GC 回收。用法很简单:
- 创建:
$weakRef = WeakReference::create($obj); - 安全取值:
$obj = $weakRef->get();—— 返回null表示已被回收 - 避免空指针:
echo $weakRef->get()?->name;(PHP 8.0+ 空合并链式调用)
比如改造购物车类,让它弱持有用户:
class Cart {private WeakReference $userRef;
public function setUser(User $user): void {
$this->userRef = WeakReference::create($user);
}
public function getUser(): ?User {
return $this->userRef->get();
}
}
WeakMap:专为对象元数据设计的“自动清理缓存”
比 WeakReference 更进一步——直接用对象作 key,值只随 key 存活。适合:
- 每对象缓存计算结果(如序列化后 JSON 字符串)
- 监听器注册表(key 是监听对象,value 是回调列表)
- ORM 实体状态映射(避免 UnitOfWork 跨请求累积)
示例:
$cache = new WeakMap();$user = new User(id: 123);
$cache[$user] = json_encode($user->toArray());
unset($user); // $cache[$user] 自动失效,内存立即可回收
配合 GC 主动验证是否真释放
别只看 memory_get_usage(),它反映的是 PHP 内存池分配量。真正要盯的是进程 RSS(常驻内存):
- 每次任务结束后调用
gc_collect_cycles(); gc_mem_caches(); - 观察 RSS 是否回落 —— 不回落,说明还有强引用钉住对象
- 用
xdebug_debug_zval()或debug_zval_dump()检查可疑变量的 refcount
如果 WeakReference 的 get() 返回 null,但 RSS 还涨,问题不在对象本身,而在闭包、静态属性、全局数组或第三方库缓存里。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











