C# - 发布本机资源

时间:2009-11-08 03:46:15

标签: c# garbage-collection clr

我对.net比较新。当我试图掌握垃圾收集的概念(来自“CLR via C#”)时,我开始了解垃圾收集方法的强大程度。但是当我读到时,我明白应该释放分配的原生资源。方法是:
i)使我们的类型派生自 CriticalFinalizerObject 类型
ii)使用使用语句

使用Dispose Pattern

我心中的疑问:
1)什么时候使用什么我有点困惑? 2)对于CLR而言,将非垃圾对象向下移动以压缩堆也不是更重要吗? 3)任何其他文章建议更彻底地阅读和理解这个概念。

如果我在上述任何陈述中弄错了,请纠正我 问候,
贾斯汀塞缪尔。

4 个答案:

答案 0 :(得分:4)

  1. 如果您的类型的使用应被视为constrained execution region或CER,则希望从CriticalFinalizerObject派生。 CER是一个代码区域,必须完全无例外地完成,根据我的经验,它们不经常使用(但这并不意味着它们没用)。

    实现IDisposable界面有点不同 - 一旦消费者不再需要它,这个界面就会提供一种确定性的清理方式。这通常用于清理非托管资源(如数据库连接和文件句柄)。

  2. 是的,垃圾收集器在紧凑阶段必须在内存中移动很多对象,但这并不是真正有用的东西。当虚拟内存碎片化时,对象将被移动,并且由于垃圾收集器完全负责托管堆,因此这是在您无法控制的范围内。在这种情况下,最佳做法是尽可能地构建您的类型,并且只有在仪器证明它​​已成为一个问题时才会担心垃圾收集器。

  3. 我会看看是否可以找到更多有用的文章,但 CLR通过C#几乎是您能够在此主题上找到的最佳信息。

答案 1 :(得分:3)

我在Dispose, Finalization, and Resource Management上推荐这篇文章。

您使用的内容在很大程度上取决于您执行的编程类型。根据个人经验,我发现:

  • 大多数时候,我唯一需要做的资源管理就是在使用块中包装任何实现IDisposable的对象。
  • 当我的类拥有一个实现IDisposable的对象时,偶尔我必须实现Basic Dispose Pattern(没有终结器)。
  • 我从未必须从CriticalFinalizerObject派生。

您的里程可能会有所不同。

答案 2 :(得分:2)

尽可能使用Dispose模式和using。仅当您无法确定地知道何时可以释放特殊资源时,才使用终结器。如果你发现这种情况经常发生,你可能会做错事。

垃圾收集是一个很深刻的话题。有关垃圾收集的概述及其在CLR中的实现,this article似乎很可靠。它来自差不多十年前,但好的CS就像是一个好的数学:它很老了。

答案 3 :(得分:0)

安全地使用非托管句柄

无法可靠地释放没有受约束执行区域(CER)的非托管句柄。你最终会遇到竞争条件,因为ThreadAbortOutOfMemory例外可以在你的终结者中间出现。所以你需要使用CERs。

CriticalFinalizerObject在内部使用约束执行区域,在最终确定期间优先处理,并且具有一些其他功能,使得“正确”并且在需要时始终释放非托管资源相对容易。通常,在保存非托管对象的句柄时,您应该从SafeHandleCriticalFinalizerObject派生。这样你知道当你的对象被垃圾收集时它们会被清理掉,即使它是ThreadAbortException之类的异常关闭情况。

使用()和IDisposable添加什么

using()和IDisposable模式允许您热切地释放非托管资源 - 只要您完成使用它们。如果您不使用using()处置对象,它们将一直存在,直到下一次垃圾收集。这是效率低下的。

所以CriticalFinalizerObject是关于确保非托管资源最终发布,而using()则是确保快速释放非托管资源。两者都应该一起使用。

using()也适用于纯托管代码,例如,如果要缓存对象池,Dispose()可以将对象返回到池中。

在GC期间压缩堆

压缩堆可以更有效,因为持续很长时间的对象最终都打包在一起。在.NET Framework中,只有最低代(最近创建的对象)才会被压缩。 Theres是在引擎盖下完成的很多优化。阅读起来很有趣,但对于完成工作并不重要。如果您想了解更多信息,请搜索“分代垃圾收集”的文章。