我对.net比较新。当我试图掌握垃圾收集的概念(来自“CLR via C#”)时,我开始了解垃圾收集方法的强大程度。但是当我读到时,我明白应该释放分配的原生资源。方法是:
i)使我们的类型派生自 CriticalFinalizerObject 类型
ii)使用使用语句
我心中的疑问:
1)什么时候使用什么我有点困惑?
2)对于CLR而言,将非垃圾对象向下移动以压缩堆也不是更重要吗?
3)任何其他文章建议更彻底地阅读和理解这个概念。
如果我在上述任何陈述中弄错了,请纠正我
问候,
贾斯汀塞缪尔。
答案 0 :(得分:4)
如果您的类型的使用应被视为constrained execution region或CER,则希望从CriticalFinalizerObject
派生。 CER是一个代码区域,必须完全无例外地完成,根据我的经验,它们不经常使用(但这并不意味着它们没用)。
实现IDisposable
界面有点不同 - 一旦消费者不再需要它,这个界面就会提供一种确定性的清理方式。这通常用于清理非托管资源(如数据库连接和文件句柄)。
是的,垃圾收集器在紧凑阶段必须在内存中移动很多对象,但这并不是真正有用的东西。当虚拟内存碎片化时,对象将被移动,并且由于垃圾收集器完全负责托管堆,因此这是在您无法控制的范围内。在这种情况下,最佳做法是尽可能地构建您的类型,并且只有在仪器证明它已成为一个问题时才会担心垃圾收集器。
我会看看是否可以找到更多有用的文章,但 CLR通过C#几乎是您能够在此主题上找到的最佳信息。
答案 1 :(得分:3)
我在Dispose, Finalization, and Resource Management上推荐这篇文章。
您使用的内容在很大程度上取决于您执行的编程类型。根据个人经验,我发现:
您的里程可能会有所不同。
答案 2 :(得分:2)
尽可能使用Dispose模式和using
。仅当您无法确定地知道何时可以释放特殊资源时,才使用终结器。如果你发现这种情况经常发生,你可能会做错事。
垃圾收集是一个很深刻的话题。有关垃圾收集的概述及其在CLR中的实现,this article似乎很可靠。它来自差不多十年前,但好的CS就像是一个好的数学:它很老了。
答案 3 :(得分:0)
安全地使用非托管句柄
无法可靠地释放没有受约束执行区域(CER)的非托管句柄。你最终会遇到竞争条件,因为ThreadAbort
或OutOfMemory
例外可以在你的终结者中间出现。所以你需要使用CERs。
CriticalFinalizerObject
在内部使用约束执行区域,在最终确定期间优先处理,并且具有一些其他功能,使得“正确”并且在需要时始终释放非托管资源相对容易。通常,在保存非托管对象的句柄时,您应该从SafeHandle
或CriticalFinalizerObject
派生。这样你知道当你的对象被垃圾收集时它们会被清理掉,即使它是ThreadAbortException
之类的异常关闭情况。
使用()和IDisposable添加什么
using()
和IDisposable模式允许您热切地释放非托管资源 - 只要您完成使用它们。如果您不使用using()
处置对象,它们将一直存在,直到下一次垃圾收集。这是效率低下的。
所以CriticalFinalizerObject
是关于确保非托管资源最终发布,而using()
则是确保快速释放非托管资源。两者都应该一起使用。
using()
也适用于纯托管代码,例如,如果要缓存对象池,Dispose()
可以将对象返回到池中。
在GC期间压缩堆
压缩堆可以更有效,因为持续很长时间的对象最终都打包在一起。在.NET Framework中,只有最低代(最近创建的对象)才会被压缩。 Theres是在引擎盖下完成的很多优化。阅读起来很有趣,但对于完成工作并不重要。如果您想了解更多信息,请搜索“分代垃圾收集”的文章。