WeakReference用于缓存、事件监听器管理及破除循环引用,不阻止GC回收目标对象;推荐用泛型WeakReference,通过TryGetTarget安全获取值,适用于内存敏感场景。

在 C# 中,WeakReference 主要用于缓存、事件监听器管理或对象图中存在循环引用的场景,它让 GC 可以在内存紧张时回收目标对象,从而避免强引用导致的内存泄漏。
WeakReference 的核心作用:不阻止垃圾回收
普通引用(如 var obj = new MyClass();)是强引用,只要还有强引用存在,GC 就不会回收该对象。WeakReference 则不同——它“弱弱地”指向一个对象,不计入 GC 的可达性判断。只要没有其他强引用,哪怕这个 WeakReference 还活着,目标对象也可能被回收。
基本用法:创建、获取、检查是否存活
推荐使用泛型版本 WeakReference(.NET 4.5+),类型安全且无需装箱:
- 创建:
var weakRef = new WeakReference- >(new List
{ 1, 2, 3 }); - 尝试获取值:
if (weakRef.TryGetTarget(out var list)) { /* list 不为 null,可用 */ } - 检查是否已回收:
bool isAlive = weakRef.TryGetTarget(out _);
非泛型 WeakReference 仍可用,但需手动类型转换和处理 IsAlive + Target(注意竞态风险,IsAlive 返回 true 后 Target 仍可能为 null)。
典型防泄漏场景:缓存与事件订阅
缓存小对象(如 UI 资源、解析结果):
用 Dictionary 缓存图片,内存不足时自动释放,下次访问时按需重建,不阻塞 GC。
解除事件订阅泄漏(尤其跨生命周期):
例如窗体 A 订阅了静态类或长生命周期服务的事件,A 关闭后若未取消订阅,会因委托持有 A 的强引用而无法回收。
可改用弱事件模式(如 WeakEventManager),或自定义弱代理包装器,让事件源不强引用订阅者。
注意事项:别把它当“自动空安全”
-
TryGetTarget是线程安全的,但获取到的对象仍可能被其他线程释放(不过 .NET GC 是全局暂停的,实际中极少发生“刚拿到就变 null”) - 不要对同一对象同时持有强引用和弱引用并依赖弱引用来“延缓释放”——这违背设计初衷,也起不到释放效果
- 频繁调用
TryGetTarget并反复重建对象,可能抵消弱引用带来的内存优势,应结合业务权衡
基本上就这些。WeakReference 不复杂,但容易忽略它的“非确定性”——你不能假设它总能取到值,也不能靠它来精确控制生命周期。合理用在缓存、解耦、破循环引用上,才是避免内存泄漏的关键。








