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
