处理问题

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

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

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

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

三个简单的规则。

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

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

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

是的 – 如果您的类“包含” IDisposable ,那么该类几乎肯定也会实现IDisposable

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

在可能的情况下,最好不要首先拥有这样的类成员 – 将它们作为局部变量的方法参数等,这样您就可以使用它们然后关闭它们,而不会将资源的生命周期与对象的生命周期联系起来。 但是,在某些情况下这是不合适的 – 在这种情况下,您应该实现IDisposable

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

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

它的长短是需要Dispose()实现IDisposable任何东西。

因为这些是您的类的私有成员变量, 并且如果它们应该在该类的实例的生命周期中可用,那么您的类也应该在它自己的Dispose()方法中实现这些类型的IDisposableDispose()

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

这里有非常全面的IDisposable指南。

从Dispose方法中过渡处理您的类型中定义的任何一次性字段。

您应该在对象生命周期控制的任何字段上调用Dispose()。 例如,考虑一下您的对象拥有私有TextReader字段的情况。 在你的类型的Dispose中,你应该调用TextReader对象的Dispose,它将依次处理它的一次性字段(例如Stream和Encoding),依此类推。 如果在Dispose(bool disposing)方法中实现,则只有在disposing参数为true时才会出现这种情况 – 在完成期间不允许触摸其他托管对象。 此外,如果您的对象不拥有给定的一次性对象,则不应尝试处置它,因为其他代码仍然可以依赖它处于活动状态。 这两者都可能导致细微的错误检测。

在您的类型被解封时实现dispose模式并包含明确需要或可以释放的资源,例如原始句柄或其他非托管资源。

此模式为开发人员提供了一种标准化方法,可以确定性地销毁或释放对象拥有的资源。 它还帮助子类正确释放基类资源。

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

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

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

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

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

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