Tec*_*one 13 .net c# garbage-collection weak-references
我有一个我希望通过的测试,但垃圾收集器的行为并不像我假设的那样:
[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
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,obj
对象应该是GC'd,因此我希望该WeakReference.IsAlive
属性返回false
.
似乎因为obj
变量声明的范围与GC.Collect
未收集的变量相同.如果我在方法之外移动obj声明和初始化,则测试通过.
有没有人对此行为有任何技术参考文档或解释?
小智 11
遇到与你相同的问题 - 我的测试到处传递,除了NCrunch(在你的情况下可能是任何其他仪器).嗯.使用SOS进行调试后,在测试方法的调用堆栈上显示了其他根.我的猜测是,它们是代码检测的结果,禁用了任何编译器优化,包括那些正确计算对象可达性的编译器优化.
这里的解决方法非常简单 - 不要从GC和测试活力的方法中获得强有力的参考.这可以通过简单的辅助方法轻松实现.下面的更改使您的测试用例通过了NCrunch,它最初失败了.
[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();
}
Run Code Online (Sandbox Code Playgroud)
sup*_*cat 10
我可以看到一些潜在的问题:
我不知道C#规范中的任何内容,它要求局部变量的生命周期是有限的.在非调试版本中,我认为编译器可以自由地省略最后一个赋值obj
(设置为null
),因为没有代码路径会导致obj
在它之后永远不会使用的值,但我希望在非debug build元数据将指示在创建弱引用之后永远不会使用该变量.在调试版本中,变量应该存在于整个函数范围内,但该obj = null;
语句应该实际清除它.尽管如此,我不确定C#规范承诺编译器不会省略最后一个语句,但仍保留变量.
如果您正在使用并发垃圾收集器,则可能会GC.Collect()
触发集合的立即启动,但该集合在GC.Collect()
返回之前实际上不会完成.在这种情况下,可能没有必要等待所有终结器运行,因此GC.WaitForPendingFinalizers()
可能过度,但它可能会解决问题.
当使用标准垃圾收集器时,我不希望存在对象的弱引用以终结器的方式延长对象的存在,但是当使用并发垃圾收集器时,它可能被放弃的对象存在弱引用被移动到具有需要清理的弱引用的对象队列,并且这种清理的处理发生在与其他所有内容同时运行的单独线程上.在这种情况下,需要调用GC.WaitForPendingFinalizers()
才能实现所需的行为.
请注意,通常不应期望弱引用将以任何特定程度的及时性无效,也不应期望Target
在IsAlive
报告为true 之后获取将引发非空引用.人们应该IsAlive
只在一个人不关心目标的情况下使用,如果目标仍然存在,但是有兴趣知道该参考已经死亡.例如,如果有一个WeakReference
对象集合,则可能希望周期性地遍历列表并删除WeakReference
目标已经死亡的对象.人们应该为WeakReferences
可能留在收集中的时间长于理想必要的时间做好准备; 如果他们这样做的唯一后果应该是轻微浪费内存和CPU时间.
归档时间: |
|
查看次数: |
3709 次 |
最近记录: |