如果不使用using语句,IDisposable内存是否会泄漏?

时间:2013-02-08 21:07:23

标签: c# idisposable

如果不使用using语句会导致IDisposable内存泄漏吗? 如果是这样,如果没有太多代码,有人可以提供内存泄漏示例吗?

6 个答案:

答案 0 :(得分:4)

一个正确编写的程序,它创建一个实现IDisposable的类型的实例,并且不知道 能够在放弃后自行清理,必须确保在放弃该实例之前调用Dispose。任何未能在没有明确知道的情况下调用Dispose类型的程序已损坏

虽然如果自动终结可以处理所有事情会很好,但这是一个非常糟糕的清理机制。它没有提供关于排序,线程上下文,及时性或完成确定性的保证(当使用确定性清理时,可以合理地确定如果清理失败,程序似乎不会正常完成;当使用最终化时,程序可以即使没有尝试清理对象,它似乎也能正常完成。

微软可能曾经打算让每个IDisposable课程在被遗弃后能够自行清理,但这根本不可行。在许多情况下,对于一个试图自行清理的类,如果放弃会增加大量的复杂性,并且只会将一个容易被追踪的明显问题的破坏程序变成一个通常有效的破坏程序除非终结器线程相对于某个其他线程的时序导致事情以某种意外和不可重现的方式失败。

有些类型尽管实施IDisposable,但无条件安全放弃,并且在某些情况下可能会安全放弃其他类型。在处理它们很困难的情况下放弃这种类型是很好的(例如,因为引用由多个对象操纵,这些对象由各种线程操纵,并且任何特定对象在持有最后一个存活时都没有很好的方法可以知道它参考),前提是一个人提出相信这种行为是安全和适当的理由。但是,如果一个人接受了IDisposable未知血统的物体,这种行为是不合适的。

答案 1 :(得分:2)

不,它不会泄漏。最终垃圾收集将绕过处理对象。

IDisposable允许调用者尽早释放资源。

<强>更新

@Servy和@Brian Rasmussen状态。实现IDisposable的类也应该实现终结器。这是推荐的做法。见http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.100).aspx

答案 2 :(得分:2)

首先,请注意 IDisposable通常涉及外部非托管资源 1 - 例如文件,连接 - 以及泄漏; GC使用的CLR对象和内存仍然可以根据可达性正确处理。

IDisposable定义合同,表示在类型中添加或删除时的重大变化。 任何不遵守此合同的行为都可能导致“行为不明确”。 using构造是避免必须处理调用Dispose和edge-cases的细节的工具。例外,但它不是合同的一部分,不是必需的。然而,合同保持不变,并且任何违反此类规定的行为都会消除所述IDisposable对“正常工作”的所有责任。

  • 实现IDisposable的某些类型永远不会泄漏资源;他们可能不会处置任何外部资源。
  • 实现IDisposable的某些类型不遵循同时实现终结器的“最佳实践”;如果没有调用Dispose,它们泄漏外部资源。
  • 某些类型(例如实现终结器模式的类型)可能仅在某些GC情况下泄漏外部资源。也就是说,可能不会很快调用终结器。这种情况可能太慢而不能成为低负载情况下的问题,但会导致高负载情况下出现意外故障。
  • 某些类型可能会导致定义不正确且状态不一致的情况。

不要违反合同。


1 IDisposable类型可能也会改变Dispose中不使用非托管资源的某些状态:如果合同,这仍属于“未明确定义的行为”被侵犯了。我使用IDisposable类型的一种情况是管理运行时可调用包装器(RCW)对象,即使它们在运行时在技术上“管理”。有关更多情况,请参阅supercat的评论。

答案 3 :(得分:1)

这完全取决于您的IDisposable是什么。

IDisposable模式基本上是一种确定性地释放托管(和非托管)资源的方法,而不是等到该对象的终结器运行。例如,如果您打开数据库连接,文件句柄等,您当然希望“按需”释放或以其他方式清理这些资源,因此它们不会阻止您重新获取其他地方的访问权限。这是Dispose模式的主要用例。

那么,它会泄漏内存吗?同样,这取决于 - 很可能,如果您正在使用IObervable<T>订阅,因为从某种意义上说,它们是未发布的事件处理程序(我在这里大大简化了)。如果不关闭SqlConnection,是否会导致内存泄漏?不是最严格的“内存泄漏”定义,因为连接最终会关闭(例如,当你的应用程序终止时,或最终收集并最终确定连接对象),但我想我可以通过说:

“始终处置您的IDisposables”

编辑:@Servy是绝对正确的 - 在我的SqlConnection示例中,我相信终结器会自动关闭连接,但这通常不保证IDisposables的行为 - 所以总是Dispose!< / p>

答案 4 :(得分:1)

using声明只是语法糖

 using(var resource = expression) statement

翻译喜欢的内容

{
   var resource = expression;
   try {
      statement;
   }
   finally {
      [if(resource!=null)]((IDisposable)resource).Dispose();
   }
}

如果正确实施了dispose模式,则不会发生内存泄漏。 GC调用(非确定性)Finalizer调用Dispose方法。

答案 5 :(得分:0)

Using语句将在块结束时调用对象Dispose方法。

您可以使用以下示例来获得相同的结果:

 obj a = new obj(); // Assuming obj : IDisposable
 try 
 {
    // Your code here
 }
 finally
 {
    if (a != null)
    { 
       a.Dispose();
    }
 }