You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WeakReference使用异常:为何无强引用时对象仍存活?

问题原因分析

你遇到的问题核心在于Debug模式下局部变量的生命周期延长,以及委托实例的引用持有逻辑:

1. Debug模式的编译器行为

在Debug构建配置下,.NET编译器会刻意延长局部变量的生命周期至方法执行结束,目的是方便调试时查看变量值。即使你已经将inst和callback设为null,之前创建的Action委托实例仍然可能被方法栈上的隐藏引用持有,导致GC无法回收该委托实例,因此WeakReference.TryGetTarget会返回true。

2. 委托实例的引用关系

你创建的WeakReference<Action>跟踪的是委托实例本身,而不是SomeClass的实例。当你通过inst.DoSomething创建委托时,这个委托对象内部持有对inst的强引用。但反过来,只要委托实例本身还有强引用存在(比如Debug模式下的栈引用),即使inst被置空,委托实例也不会被GC回收,WeakReference自然会判定目标存活。

验证与解决方法

  • 切换到Release模式运行测试:Release模式下编译器会优化局部变量生命周期,不再保留无用的引用,GC会正常回收委托实例,此时第二次TryGetTarget会返回false。
  • 修改测试逻辑,直接跟踪SomeClass实例而非委托:如果你的目标是验证SomeClass实例的存活状态,应该创建WeakReference<SomeClass>而非WeakReference<Action>,这样逻辑更直接,也能避免委托实例带来的干扰。示例代码如下:
[TestMethod]
public void TestLifeOfObject()
{
    SomeClass target;

    var inst = new SomeClass();
    var weakRef = new WeakReference<SomeClass>(inst);

    GcHelper.Collect();
    Debug.WriteLine($"weakRef.Target is alive = {weakRef.TryGetTarget(out target)}, expected true because inst keep a hold on SomeClass.");

    inst = null;
    GcHelper.Collect();
    Debug.WriteLine($"weakRef.Target is alive = {weakRef.TryGetTarget(out target)}, expected false, because there is no more ref on SomeClass.");
}

内容的提问来源于stack exchange,提问作者Eric Ouellet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 14:30:43