我有一个测试,我预计通过,但垃圾收集器的行为不是我推测的:
[Test] public void WeakReferenceTest2() { var obj = new object(); var wRef = new WeakReference(obj); wRef.IsAlive.Should().BeTrue(); //passes GC.Collect(); wRef.IsAlive.Should().BeTrue(); //passes obj = null; GC.Collect(); wRef.IsAlive.Should().BeFalse(); //fails }
在这个例子中,obj对象应为GC’d,因此我希望WeakReference.IsAlive属性返回false.@H_301_5@
看来,因为obj变量被声明在与GC.Collect相同的范围内,所以它没有被收集.如果我将对象声明和初始化移动到测试通过的方法之外.@H_301_5@
有没有人有任何技术参考文献或解释这个行为?@H_301_5@
解决方法
遇到同样的问题,我的测试通过无处不在,除了NCrunch之外(可能是您的情况下的任何其他工具).嗯.使用SOS进行调试会在测试方法的调用堆栈上显示额外的根.我的猜测是,它们是禁用任何编译器优化的代码工具的结果,包括正确计算对象可达性的编译器优化.
这里的治疗是非常简单的 – 从来没有强调GC的方法和对活性的测试.这可以通过简单的帮助方法轻松实现.以下更改使您的测试用例与NCrunch通过,最初出现故障.@H_301_5@
[TestMethod] public void WeakReferenceTest2() { var wRef2 = CallInItsOwnScope(() => { var obj = new object(); var wRef = new WeakReference(obj); wRef.IsAlive.Should().BeTrue(); //passes GC.Collect(); wRef.IsAlive.Should().BeTrue(); //passes return wRef; }); GC.Collect(); wRef2.IsAlive.Should().BeFalse(); //used to fail,now passes } private T CallInItsOwnScope<T>(Func<T> getter) { return getter(); }