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

本文关键字:内存 是否 泄漏 IDisposable using 语句 如果不 | 更新日期: 2023-09-27 17:58:29

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

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

一个正确编写的程序,它创建一个实现IDisposable的类型的实例,并且没有特别知道在放弃时能够充分清理自身,必须确保在放弃该实例之前在该实例上调用Dispose。 任何无法调用Dispose的类型的程序,如果没有它,它就没有被破坏

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

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

有些类型尽管实施了IDisposable,但可以无条件地安全放弃,而其他一些类型在某些情况下可以安全地放弃。 在难以处理它们的情况下放弃这些类型是可以的(例如,因为引用由由各种线程操作的多个对象持有,并且任何特定对象在保存最后一个幸存的引用时都没有很好的方法可以知道它(,只要一个人记录一个人相信这种行为是安全和适当的理由。 然而,在接受IDisposable未知血统的对象的情况下,这种行为是不合适的。

不,它不会泄漏。 最终,垃圾回收将用于处理对象。

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

更新

正如拉斯穆森@Servy和@Brian所说。 实现IDisposable的类也应该实现终结器。 这是建议的做法。 参见 http://msdn.microsoft.com/en-US/library/B1yfkh5E(v=vs.100(.aspx

首先,请注意,IDisposable 通常与外部非托管资源1 相关 - 例如文件、连接 - 以及此类泄漏;此类使用的 CLR 对象和内存仍将由 GC 根据可访问性正确处理。

IDisposable 定义协定,并在添加到类型或从类型中删除时表示中断性更改。任何不履行此合同的行为都可能导致"定义不明确的行为"。using构造是一种工具,用于避免处理调用 Dispose 和边缘情况的细节,但它不是协定的一部分,也不是必需的。然而,合同保持不变,任何违反此类行为的行为都会消除所述IDisposable"正常工作"的所有责任。

  • 实现 IDisposable 的某些类型永远不会泄漏资源;它们可能不会释放任何外部资源。
  • 某些实现 IDisposable 的类型不遵循实现终结器的"最佳实践";如果不调用 Dispose,它们泄漏外部资源。
  • 某些
  • 类型(例如也实现终结器模式的类型(可能仅在某些 GC 情况下泄漏外部资源。也就是说,可能不会很快调用终结器。这种情况可能太慢,在低负载方案中不会成为问题,但在高负载方案中会导致意外故障。
  • 某些类型可能会导致行为定义不明确和状态不一致的情况。

不要违反合同。


1 IDisposable 类型还可以更改 Dispose 中不利用非托管资源的某些状态:如果违反合同,这仍包含在"未明确定义的行为"中。我使用 IDisposable 类型的一种情况是管理运行时可调用包装器 (RCW( 对象,即使它们在技术上由运行时"管理"。有关更多情况,请参阅超级猫的评论。

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

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

那么,它会泄漏内存吗?同样,这取决于 - 如果您使用的是IObervable<T>订阅,则很可能,因为从某种意义上说,它们是未发布的事件处理程序(我在这里大大简化了(。如果不关闭该SqlConnection会导致内存泄漏吗?不是按照"内存泄漏"的最严格定义,因为连接最终会关闭(例如,当您的应用程序终止时,或者最终收集和完成连接对象时(,但我想我可以总结所有这些

"始终处理您的身份证件">

编辑:@Servy是绝对正确的 - 虽然在我的SqlConnection示例中,我相信终结器会自动关闭连接,但这并不能保证一般IDisposables的行为 - 所以总是处理!

using语句只是语法糖

 using(var resource = expression) statement

翻译为喜欢的东西

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

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

Using语句将在块的末尾调用对象Dispose方法。

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

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