WeakReference的核心用途是在不阻止GC回收的前提下临时持有对象,适用于大对象缓存、事件监听器防泄漏和打破循环引用;必须用TryGetTarget安全访问Target,避免NullReferenceException。
WeakReference 的核心用途是:在不阻止 GC 回收的前提下,临时“惦记着”一个对象——它不是为了长期持有,而是为了“有就用,没了再建”。
WeakReference 最典型的使用场景它不是万能胶,而是专治几类特定问题的“止痛贴”:
WeakReference 正好卡在这个平衡点。
Unsubscribe,控件就永远被强引用链拴住——改用弱引用管理订阅者(需配合自定义事件代理),可让控件随 UI 一起被回收。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 这张牌。