21

如果 .NET 有垃圾收集,那么为什么必须显式调用IDisposable

4

6 回答 6

49

垃圾收集是为了内存。您需要处理非内存资源 - 文件句柄、套接字、GDI+ 句柄、数据库连接等。这通常是IDisposable类型的基础,尽管实际句柄在引用链中可能有很长的路要走。例如,您可能会处理一个Dispose它有一个引用的对象,它会处理有一个引用的对象,这会释放文件句柄本身。XmlWriterStreamWriterFileStream

于 2009-03-05T14:56:00.060 回答
9

扩展一下其他评论:

应该对所有引用非托管资源的对象调用 Dispose() 方法。此类示例包括文件流、数据库连接等。大多数情况下有效的基本规则是:“如果 .NET 对象实现了 IDisposable,那么当您完成该对象时,您应该调用 Dispose()。

但是,还有一些其他的事情要记住:

  • 调用 dispose 并不能让您控制对象实际销毁和内存释放的时间。GC 为我们处理了这个问题,并且做得比我们做得更好。
  • 正如 Jon 所指出的,Dispose 会清理所有本地资源,一直到基类堆栈的下方。然后它调用 SuppressFinalize() 来指示对象已准备好被回收并且不需要进一步的工作。GC 的下一次运行将清理它。
  • 如果没有调用 Dispose,那么 GC 会找到需要清理的对象,但必须先调用 Finalize,以确保释放资源,对 Finalize 的请求排队等待 GC 继续,因此缺少调用 Dispose 会强制再运行一次 GC,然后才能清理对象。这会导致对象被提升到下一代“GC”。这可能看起来没什么大不了的,但在内存压力应用程序中,将对象提升到更高代的 GC 可以将高内存应用程序推向内存不足的应用程序。
  • 除非绝对需要,否则不要在您自己的对象中实现 IDisposable。实施不当或不必要的实施实际上会使事情变得更糟而不是更好。可以在这里找到一些很好的指导:

    实现 Dispose 方法

    或者阅读 MSDN 关于垃圾收集的整个部分

于 2009-03-05T15:36:25.033 回答
5

因为对象有时会在内存之外拥有资源。GC释放内存;IDisposable 是为了让你可以释放其他任何东西。

于 2009-03-05T14:56:17.453 回答
1

因为您想控制对象持有的资源何时被清理。

看,GC 是有效的,但它会在需要时这样做,即使这样,您添加到对象的终结器也只会在 2 次 GC 收集后被调用。有时,您想立即清理这些对象。

这是使用 IDisposable 的时候。通过显式调用 Dispose() (或使用 using 块的语法糖),您可以访问对象以标准方式清理自身(即您可以实现自己的 cleanup() 调用并显式调用它)

您希望立即清理的示例资源是:数据库句柄、文件句柄、网络句柄。

于 2009-03-05T14:58:07.670 回答
1

为了使用 using 关键字,对象必须实现 IDisposable。 http://msdn.microsoft.com/en-us/library/yh598w02(VS.71).aspx

于 2009-03-05T20:17:39.930 回答
0

IDisposable接口通常用资源来描述,但大多数这样的描述都没有真正考虑“资源”的真正含义。

一些对象需要要求外部实体代表他们做某事,以损害其他实体,直到另行通知。例如,包含文件流的对象可能需要请求文件系统(可能位于连接的 Universe 中的任何位置)授予对文件的独占访问权限。在许多情况下,对象对外部实体的需求将与外部代码对对象的需求相关联。例如,一旦客户端代码完成了与上述文件流对象相关的所有操作,该对象将不再需要对其关联文件具有独占访问权(或任何访问权)。

一般来说,要求实体做某事直到另行通知的对象 X 会产生交付此类通知的义务,但只要 X 的客户可能需要 X 的服务,就不能交付此类通知。的目的IDisposable是提供一种统一的方式让对象知道不再需要他们的服务,以便他们可以通知代表他们行事的实体(如果有的话)不再需要他们的服务。调用的代码IDisposable既不需要知道也不需要关心对象从外部实体请求了什么(如果有)服务,因为IDisposable只是邀请对象履行对外部实体的义务(如果有的话)。

用“资源”的术语来说,当一个对象要求外部实体代表它做某事(通常,但不一定,授予对某物的独占使用权)直到另行通知时,它会获取资源,并在它释放资源时释放资源告诉外部实体不再需要其服务。获取资源的代码不会获得“东西”,而是会产生义务;释放资源并没有放弃“事物”,而是履行了一项义务。

于 2017-06-26T15:09:38.443 回答