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
相关产品推荐
相关产品推荐

