WeakReference的核心用途是在不阻止GC回收的前提下临时持有对象,适用于大对象缓存、事件监听器防泄漏和打破循环引用;必须用TryGetTarget安全访问Target,避免NullReferenceException。

WeakReference 的核心用途是:在不阻止 GC 回收的前提下,临时“惦记着”一个对象——它不是为了长期持有,而是为了“有就用,没了再建”。
WeakReference 最典型的使用场景
它不是万能胶,而是专治几类特定问题的“止痛贴”:
-
大对象缓存:比如一个 50MB 的图像预处理结果、一棵深层嵌套的树视图数据。用户切走页面后,你不想强留它占内存,但返回时又希望“如果还在,就直接用”,
WeakReference正好卡在这个平衡点。 -
事件监听器防泄漏:UI 控件订阅了 ViewModel 的事件,但 ViewModel 生命周期更长。若不手动
Unsubscribe,控件就永远被强引用链拴住——改用弱引用管理订阅者(需配合自定义事件代理),可让控件随 UI 一起被回收。 -
避免循环引用导致的内存滞留:父对象持子对象强引用没问题,但子对象反过来强引用父对象,就容易形成 GC 不动的“孤岛”。把子→父的引用换成
WeakReference,就能打破僵局。
WeakReference 的两个构造函数参数差异很关键
别只用无参构造!trackResurrection 这个布尔值决定的是“对象被终结器复活后,弱引用还作不作数”:
-
new WeakReference(obj)→ 短弱引用(GCHandleType.Weak):终结器执行前就清空Target。对象一旦进 finalization 队列,你就再也拿不到它了。 -
new WeakReference(obj, true)→ 长弱引用(GCHandleType.WeakTrackResurrection):即使对象被GC.ReRegisterForFinalize(this)复活,Target仍可能非 null(但极罕见,且不可靠)。
绝大多数业务场景选默认(false)就够了;除非你在写底层框架、对象池,且明确需要感知复活状态,否则加 true 只会增加不确定性。
访问 Target 前必须检查,否则必崩
这是新手踩坑最密集的地方:弱引用不是“延迟加载”,而是“随时可能消失”。下面这段代码看着合理,实则危险:
主页面上引用了三个页面也说不过去呀。本次主要是把数据库合并了一下,至于功能,没有加什么新的东西,还是那些:在线订购、帐单查询(添加了一个打印的连接)、特价商品列表、热买商品列表、留言本(许多朋友说以前的那个有问题,现在换成枫叶阁女士留言本,挺不错的)、新闻、完善的管理
var weak = new WeakReference(myBigObject); // ... 一段时间后 var obj = weak.Target as MyType; // ❌ Target 可能已是 null! obj.DoSomething(); // NullReferenceException!
正确姿势永远是:
if (weak.TryGetTarget(out MyType obj))
{
obj.DoSomething(); // ✅ 安全
}
else
{
// 重建或跳过
}
注意:IsAlive 属性已过时(.NET 5+ 标记为 obsolete),它不能保证 Target 非 null —— 因为 GC 可能在 IsAlive == true 后瞬间回收对象,紧接着 Target 就变 null。所以务必用线程安全的 TryGetTarget。
真正难的不是写对那几行代码,而是想清楚:这个对象“值得弱引用吗?”——太小(如 int 包装、短字符串)不值得;重建成本太高(如需远程调用 DB 初始化)也不适合;只有“大 + 易重建 + 访问频次低”的对象,才配得上 WeakReference 这张牌。









