处理问题

时间:2011-08-30 19:27:56

标签: c# .net dispose

我有许多类具有实现IDisposable的私有成员变量(定时器,画笔等)。我是否需要做任何事情来确保.NET Framework正确清理这些变量?

我遇到的文献是指“托管资源”与“非托管资源”。这些术语让我感到困惑,因为您可以拥有一个使用非托管资源实现功能的托管类。这被认为是“非托管资源”还是“托管资源”?

我的理解是,如果您没有在实现IDisposable的对象上调用Dispose(),那么在应用程序退出之前不会释放资源。在长时间运行程序时,这种情况可能会导致OutOfMemory异常。

如何确保我的代码正确处理资源管理?这对于这些对象很重要,因为它们是自定义控件,并且可能有很多绘图消耗了IDisposable资源。我尽可能使用C#using语句,但有时我需要使一个对象实现IDisposable一个成员变量,而using语句对我没有帮助。

7 个答案:

答案 0 :(得分:9)

是的 - 如果您的班级“包含”IDisposable,该类几乎肯定会实现IDisposable

“托管”资源基本上都是内存。 “非托管”资源可以是文件句柄,网络连接,图形对象的句柄等。在大多数情况下,直接访问本机句柄的类型具有终结器,因此资源将在某个时候释放,但是明确地释放它仍然更好 - 在某些情况下(例如使用HttpWebResponse)可以使用有限数量的此类资源(在这种情况下,连接池中的连接到单个主机)并且您最终可以超时等待“死”资源被释放。

如果可能的话,首先让这些类成员更好 - 将它们作为局部变量的方法参数等,这样你就可以使用它们然后关闭它们而不会占用它们的生命周期对象生命周期的资源。但是,在某些情况下这是不合适的 - 在这种情况下,您应该实施IDisposable

答案 1 :(得分:8)

Three simple rules.

托管资源是实现IDisposable的任何内容。非托管资源类似于通过p / Invoke获得的HANDLE。像SafeHandle这样的类(或者从SafeHandle派生的类)拥有非托管资源,但它本身被视为托管资源。因此,拥有非托管资源的任何类本身都是托管资源。

由于您拥有拥有托管资源的类,请遵循规则2:实现IDisposable(但不是终结器)。

IDisposable允许更早的清理。如果你没有打电话,那么无论如何都要清理 的资源(它们不会在进程退出之前一直存在);它们只是稍后会被清理掉,并且当 它们被清理时你无法选择。

答案 2 :(得分:1)

如果您的类具有实现IDisposable的成员变量,那么您的类也应该实现它。你清理你拥有的东西。

答案 3 :(得分:1)

您的理解中有一些好的信息和一些错误的信息。

您需要Dispose()实施IDisposable的所有内容。

由于这些是您的类的私有成员变量,如果这些变量应该在该类的实例的生命周期中可用,那么您的类也应该实现IDisposable和{这些类型的{1}}位于自己的Dispose()方法中。

如果这些私有成员变量的生命周期有限(即只在一个方法内),只需将它们包装在Dispose()块中。

答案 4 :(得分:1)

非常全面的IDisposable指南here

  

传递性地处理您的类型中定义的任何一次性字段   来自您的Dispose方法。

     

您应该在任何字段上调用Dispose()   其生命周期是您的对象控制的。例如,考虑一个案例   您的对象拥有私有TextReader字段的位置。在你的类型   Dispose,你应该调用TextReader对象的Dispose   反过来处理其一次性领域(Stream和Encoding,for   例子),等等。如果在Dispose内部实现(bool处理)   方法,这应该只在disposing参数是   在此期间不允许使用真实触摸的其他托管对象   定稿。此外,如果您的对象不拥有给定的对象   一次性物品,不应该像其他物品那样试图处理它   代码仍然可以依赖它处于活动状态。这两者都可能导致   微妙的检测错误。

     

在您的类型未密封时执行配置模式   包含明确需要或可以释放的资源   示例原始句柄或其他非托管资源。

     

这种模式   为开发人员提供确定性的标准化方法   销毁或释放对象拥有的资源。它还有助于子类   正确释放基类资源。

'非托管资源'通常是指代码引用本机句柄直接(文件句柄,连接,套接字等)的情况。在这种情况下,您还必须实现终结器或使用SafeHandle。大多数情况下,您通过.NET类(如TextReader)引用本机句柄间接。在这种情况下,您可以简单地使用“使用”,或者,如果您正在编写库,则可以传递实现IDisposable。

答案 5 :(得分:0)

1)你可以使用Memory Profiler工具,网上有很多,我知道最好的是Reg Gate的ANTS Profiler。

2)我的经验法则是事件必须始终是取消订阅的,如果它们是成员变量并且持有它们的对象被破坏,则一次性对象(Streams等)将被自动处理。 例如,如果在方法中创建本地一次性对象,则必须对其进行处理,或者将其放在using语句中并忘记它;)

答案 6 :(得分:0)

我认为描述托管资源是一个实现IDisposable并需要清理的类型对象是最有帮助的,但如果它被放弃而没有正确处理,则可以执行此类清理(通常使用Finalize)。非托管资源通常是指需要清理的实体,如果在没有首先使用Dispose的情况下放弃它就不会发生。重要的是要注意,术语“托管资源”基本上只指类类对象(通常覆盖Finalize,但在某些情况下可能是WeakReference对象的目标),非托管资源可能不仅仅是任何,它们也可能任何地方,包括在另一台计算机上。

我建议不要使用术语“资源”,而是从“责任”的角度思考。打开文件或套接字连接会产生关闭它的责任。获取锁会产生释放它的责任。向远程系统发送“授予我对此记录的独占访问权”消息会产生向其发送“我已完成此记录”消息的责任。如果一个对象的清理责任即使被废弃也可以执行,那么它就是一个“托管资源”。否则,它是一个“非托管资源”。

仅仅将事物归类为“托管资源”或“非托管资源”并不足以决定如何清理它们。一些非托管职责可以通过类型包装器方便地处理,该包装器可以在不适当的放弃的情况下执行任何必要的清理。这种包装器通常应包含执行清理责任所需的最少量信息。其他责任不能自动处理。通常最好确保调用Dispose而不是尝试处理可能发生的所有事情。