C# WeakReference是什么 - 创建对对象的弱引用,允许GC回收

WeakReference 是 C# 中不阻止 GC 回收对象的引用类型,适用于缓存、事件监听管理等场景;需通过 Target 或 TryGetTarget 检查有效性,推荐使用泛型 WeakReference。

WeakReference 是 C# 中一种特殊的引用类型,它不阻止垃圾回收器(GC)回收其所指向的对象。换句话说,只要没有强引用指向该对象,即使存在 WeakReference,GC 仍可在下一次回收周期中将其回收。

为什么需要 WeakReference?

常用于缓存、事件监听器管理、大对象临时持有等场景,避免因引用导致对象长期驻留内存,造成内存泄漏或资源浪费。

  • 比如缓存图像数据:用 WeakReference 持有,内存紧张时自动释放,下次需要时再重建
  • 比如 UI 控件订阅事件后忘记取消:用弱引用持有订阅者,避免控件已销毁但事件源仍强引用它

如何创建和使用 WeakReference

创建后需通过 Target 属性访问对象,并始终检查是否为 null(已被回收):

var obj = new byte[1024 * 1024]; // 1MB 对象
WeakReference weakRef = new WeakReference(obj);

obj = null; // 切断强引用 GC.Collect(); // 主动触发回收(仅调试用)

if (weakRef.Target is byte[] recovered) { Console.WriteLine("对象还在"); } else { Console.WriteLine("对象已被回收"); }

WeakReference — 泛型版本更安全

推荐使用泛型版 WeakReference,避免装箱/拆箱,类型安全,且提供 TryGetTarget(out T target) 方法,语义更清晰:

  • TryGetTarget 返回 bool 表示是否成功获取,同时输出目标对象
  • 无需类型转换,无运行时异常风险
  • 性能略优,尤其对值类型或频繁访问场景

注意点和常见误区

WeakReference 不是“延迟回收开关”,它不控制 GC 行为,只被动反映对象存活状态

  • GC 是否回收取决于当前内存压力、代龄、根引用等,WeakReference 无法预测或干预
  • 不要在多线程中直接多次访问 Target,应先用 TryGetTarget 获取一次并缓存结果
  • 不能用于跨 AppDomain 或序列化场景(.NET Core/.NET 5+ 已无 AppDomain)

基本上就这些。WeakReference 本身不复杂,但容易忽略“对象随时可能消失”这一本质,正确使用的关键是:始终检查有效性、避免重复解引用、优先选泛型版本。