垃圾收集与IDisposable

时间:2011-05-26 20:11:49

标签: c# .net collections resources idisposable

我正和一个人谈论使用()声明。

他说如果我们不对像StreamWriter这样的东西使用using()语句,如果发生任何异常,资源将永远不会被收集。

我理解使用using()语句,但我不同意永远不会收集资源。我认为using()语句最后会调用dispose()方法,这可以使集合更快。但是,即使我们不使用using(),我们也不会调用dispose(),但仍然可以通过gabage收集来收集资源,尽管可能需要更长的时间。

你同意谁?

PS。我知道你们都在说什么。使用using()语句很重要。我只是想知道如果我们不这样做,资源肯定永远不会被收集?

7 个答案:

答案 0 :(得分:10)

我们要清楚这一点。假设有问题的资源是文件句柄。垃圾收集器知道 nothing 有关文件句柄或如何释放它。文件句柄只是一个整数。

如果持有文件句柄的StreamWriter被垃圾收集,那么垃圾收集器会将该对象放到终结队列上。当终结队列运行时,它将调用该对象的终结器, 即释放文件句柄。

这一切都清楚了吗?垃圾收集器不释放资源;垃圾收集器知道的唯一资源是内存中的对象。在释放对象之前,它已经完成,因此对象本身知道如何释放资源。

答案 1 :(得分:4)

using(x)是确定性模式。它确保在执行流中的特定点传递时在实现者上调用Dispose()。另一方面,GC不是确定性的,因为您不确切知道何时实际处置该对象。 using确保对象将在您预期时执行其清理代码(无论是什么),而不是将来的某个时间。

答案 2 :(得分:2)

如果没有对StreamWriter的引用,它最终将被垃圾收集,但它取决于垃圾收集器 - 当它是 - 它不是确定性的,所以你应该总是使用using块可以。

答案 3 :(得分:1)

使用Dispose()对象后,应始终致电IDisposableusing语句是确保遵守此规则的绝佳工具。

IDisposable的目的是允许类处理已分配的非托管资源,这些资源不会被垃圾回收自动清理。

如果你在完成后没有调用IDisposable就使用了Dispose()对象,那么即使在垃圾被收集之后,也存在永远不会正确处理资源的风险。

这就是using语句存在的原因;它为使用IDisposable对象提供了方便的语法,并定义了可以使用这些对象的明确范围。

另请注意,垃圾收集器从不调用Dispose()本身,但请注意,建议您遵循Finalize/Dispose pattern as documented on MSDN。如果对象遵循Finalize / Dispose模式,则在GC调用终结器时将调用Dispose()

答案 4 :(得分:1)

  

我正和一个人谈论使用()语句。他说如果我们不对像StreamWriter这样的东西使用using()语句,如果发生任何异常,资源将永远不会被收集。

using语句与垃圾收集无关。一旦对象没有实时引用,它就有资格进行垃圾收集。

  

我理解使用using()语句,但我不同意永远不会收集资源。

哦,那你是对的。

  

我认为using()语句最后会调用dispose()方法,这样可以使集合更快。

它可能会也可能不会使收集更快。 dispose方法通常调用GC.SupressFinalize(object),这意味着在对象被垃圾回收时不会调用终结器。相反,将简单地收集该对象。所以这可以使收集更快。

如果您打算说它会立即收集对象而不是稍后收集,那么这将是不正确的。每当垃圾收集器到达它时,都会收集符合条件的对象,一旦对象没有实时引用就会符合条件,using语句对此几乎没有影响。实际上,由于using语句的finally块包含一个实时引用,我可以想象它可能会增加对象的生命周期,但这种效果不是一个考虑因素,因为控制一个对象的生命周期不是使用的重点。确定性地处置非托管资源是使用声明的重点。

  

但是,即使我们不使用using(),我们也不会调用dispose(),但仍然可以通过gabage收集来收集资源,尽管可能需要更长的时间。

同样,使用和Dispose通常不会影响对象的生命周期。它只影响非托管资源的状态(假设Dispose方法正确实现)。你说对象仍然是正确的。

答案 5 :(得分:0)

使用与以下内容基本相同(如果您怀疑,请检查两者的IL):

 try
 { 
      IDisposable o = new Object();
 }
 finally
 {
      o.Dispose();
 }

只要有问题的对象实现了IDisposable,就会调用Dispose()方法,并且在Dispose()中处理愚蠢代码的资源将被Garbage Collected。什么时候?这不是我能回答的问题。

项目是否可能永远不会被GC。好吧,从来没有很长一段时间,但理论上如果它超越第一代并且只是坐在那里是可能的。一个问题?不,如果最终需要内存,它将被清除。经常看到,不正确,作为内存泄漏?当然可以。

答案 6 :(得分:0)

如果使用Stream创建StreamWriter,即使在StreamWriter被放弃之后,其他代码也将使用Stream,则不得在StreamWriter上调用Dispose。如果流在被提供给StreamWriter后将由其所有者放弃,那么为了正确,必须在StreamWriter上调用Dispose。

回想起来,StreamWriter可能应该有一个无用的IDisposable实现,但有一个后代类StreamOwningWriter,其实现将处理传入的流。或者,它可能有一个构造函数参数和属性,以指示在调用自己的Dispose方法时是否应该处理流。如果采用这些方法中的任何一种,那么正确的行为总是在StreamWriter上调用Dispose(并让“StreamWriter”(可能是StreamWriter或StreamOwningWriter)担心Dispose是否应该实际执行任何操作) 。