处理问题

本文关键字:处理问题 | 更新日期: 2023-09-27 18:06:58

我有一些类,它们有实现IDisposable的私有成员变量(计时器,画笔等)。我需要做些什么来确保这些变量被。net框架正确地清理吗?

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

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

我怎么能确保我的代码是正确处理资源管理?这对这些对象来说很重要,因为它们是自定义控件,并且可能会有很多消耗一次性资源的绘图。只要有可能,我就使用c# using语句,但有时我需要使一个对象实现IDisposable成员变量,而using语句在那里帮不上忙。

处理问题

三个简单规则。

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

既然你有一个拥有托管资源的类,遵循规则2:实现IDisposable(但不是终结器)。

IDisposable允许更早的清理。如果你不调用它,资源无论如何都会被清理(它们不会一直挂在那里直到进程退出);它们稍后会被清理,当被清理时,您无法选择

是的-如果你的类"包含"一个IDisposable,这个类应该几乎肯定也实现IDisposable

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

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

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

传递地处置类型中定义的任何可处置字段

您应该对任何字段调用Dispose()对象控制其生命周期。例如,考虑一个案例你的对象拥有一个私有TextReader字段。在你的类型处置,你应该调用TextReader对象的处置然后处置它的可处置字段(流和编码,for例),等等。如果在Dispose(bool Dispose)中实现方法,只有在处理参数为时才会发生期间不允许真实触摸其他托管对象终结。另外,如果你的对象不拥有给定的一次性物品,就不应该像其他物品一样试图丢弃它代码仍然可以依赖于它处于活动状态。这两种情况都可能导致subtle-to-detect bug。

当你的类型是未密封的和包含需要显式释放或可以显式释放的资源

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

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

如果你的类有实现IDisposable的成员变量,那么你的类也应该实现它。

你的理解有一些好的信息,也有一些错误的信息。

总而言之,你需要Dispose()任何实现IDisposable的东西。

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

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

1)你可以使用内存分析器工具,网络上有很多,我知道最好的是Reg Gate的ANTS分析器。

2)我的经验法则是,事件必须总是取消订阅,如果一次性对象(流等)是成员变量,并且持有它们的对象被销毁,则会自动处理。例如,如果您在方法中创建了一个局部可丢弃对象,则必须将其丢弃,或者只是将其放入using语句中并忘记它;)

我认为将托管资源描述为实现IDisposable并需要清理的类类型对象是最有帮助的,但如果它被丢弃而未被正确处置,则可以执行此类清理(通常使用Finalize)。非托管资源通常指的是需要清理的实体,如果不首先进行Dispose处理就将其丢弃,则不会进行清理。值得注意的是,虽然术语"托管资源"本质上专门指类类型对象(通常覆盖Finalize,但在某些情况下可能是WeakReference对象的目标),但非托管资源可能不仅是任何,还可能是任何,包括在另一台计算机上。

我建议不要用"资源"这个词,用"责任"这个词来思考会更有帮助。打开文件或套接字连接会创建一个关闭它的责任。获取锁会产生释放锁的责任。向远程系统发送"授予我对该记录的独占访问权"消息创建了向其发送"我已完成此记录"消息的责任。如果一个对象的清理职责即使被放弃也能被执行,那么它就是一个"托管资源"。否则,它就是一个"非托管资源"。

仅仅将事物分类为"托管资源"或"非托管资源"对于决定如何清理它们是不够的。一些非托管职责可以由类类型包装器方便地处理,该类包装器可以在不当放弃的情况下执行任何必要的清理。这样的包装器通常应该包含执行清理职责所需的最少数量的信息。其他责任不能很好地自动处理。通常,确保Dispose被调用比尝试处理未调用时可能发生的所有事情要好得多。