Garbage Collection should have removed object but WeakReference.IsAlive still returning true(垃圾收集应该已删除对象,但 WeakReference.IsAlive 仍返回 true)
问题描述
我有一个我希望通过的测试,但垃圾收集器的行为并不像我想象的那样:
I have a test that I expected to pass but the behavior of the Garbage Collector is not as I presumed:
[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
.
In this example the obj
object should be GC'd and therefore I would expect the WeakReference.IsAlive
property to return false
.
似乎因为 obj
变量被声明在与 GC.Collect
相同的范围内,所以它没有被收集.如果我将 obj 声明和初始化移到测试通过的方法之外.
It seems that because the obj
variable was declared in the same scope as the GC.Collect
it is not being collected. If I move the obj declaration and initialization outside of the method the test passes.
是否有人对此行为有任何技术参考文档或解释?
Does anyone have any technical reference documentation or explanation for this behavior?
推荐答案
遇到和你一样的问题 - 我的测试到处都通过了,除了在 NCrunch 下(在你的情况下可能是任何其他仪器).嗯.使用 SOS 进行调试会发现在测试方法的调用堆栈上保留了额外的根.我的猜测是,它们是禁用任何编译器优化的代码检测的结果,包括那些正确计算对象可达性的优化.
Hit the same issue as you - my test was passing everywhere, except for under NCrunch (could be any other instrumentation in your case). Hm. Debugging with SOS revealed additional roots held on a call stack of a test method. My guess is that they were a result of code instrumentation that disabled any compiler optimizations, including those that correctly compute object reachability.
这里的解决方法很简单 - 永远不要持有来自执行 GC 和测试活动性的方法的强引用.这可以通过简单的辅助方法轻松实现.下面的更改使您的测试用例在 NCrunch 中通过,而它最初是失败的.
The cure here is quite simple - don't ever hold strong references from a method that does GC and tests for aliveness. This can be easily achieved with a trivial helper method. The change below made your test case pass with NCrunch, where it was originally failing.
[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();
}
这篇关于垃圾收集应该已删除对象,但 WeakReference.IsAlive 仍返回 true的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:垃圾收集应该已删除对象,但 WeakReference.IsAlive 仍返回 true
- 在哪里可以找到使用中的C#/XML文档注释的好例子? 2022-01-01
- 良好实践:如何重用 .csproj 和 .sln 文件来为 CI 创建 2022-01-01
- Web Api 中的 Swagger .netcore 3.1,使用 swagger UI 设置日期时间格式 2022-01-01
- C#MongoDB使用Builders查找派生对象 2022-09-04
- MoreLinq maxBy vs LINQ max + where 2022-01-01
- WebMatrix WebSecurity PasswordSalt 2022-01-01
- 如何用自己压缩一个 IEnumerable 2022-01-01
- C# 中多线程网络服务器的模式 2022-01-01
- 输入按键事件处理程序 2022-01-01
- 带有服务/守护程序应用程序的 Microsoft Graph CSharp SDK 和 OneDrive for Business - 配额方面返回 null 2022-01-01