我今天与我的同事进行了一次对话,她说她刚刚了解了使用using
声明背后的原因。
//Using keyword is used to clean up resources that require disposal (IDisposable interface).
using (StreamReader reader = new StreamReader(@"C:\test.txt"))
{
string line = reader.ReadLine();
}
我指出该对象标记为"可以处理"但除非GC决定这样做,否则不会实际处理和垃圾收集。
她回答说,一旦using语句结束,该对象将自动处理,因为using语句被转换为try-catch-finally块。因此,对象必须放在using语句的最后。
我对此感到困惑,因为我知道使用using
语句并不能保证对象被GC收集。所有发生的事情都是调用Dispose()
方法。 GC无论如何都决定GC。但当她要求提供证据时,我找不到任何证据。
有谁知道这是如何运作的,以及如何证明它?
答案 0 :(得分:41)
你在谈论两件截然不同的事情。
一旦using
- 块结束,对象将被处理掉。这并没有说明垃圾收集的时间。释放堆内存的唯一时间是垃圾收集发生时 - 仅在内存压力下发生(除非您明确使用GC.Collect
)。
处理对象只是意味着调用其Dispose
方法。这通常意味着释放稀缺资源或本机资源(实际上,所有稀缺资源都是本机 - 套接字,文件......)。现在,在您的情况下,一次性物体的寿命在范围上是有限的,因此理论上可以在using
- 块结束后立即收集 - 但是,这并不是实际上真的发生了,因为.NET运行时试图避免收集 - 它们很昂贵。因此,在您跨越内存分配阈值之前,即使堆上有死对象,也不会发生任何集合。
那么Dispose
的重点是什么?与托管内存无关。你并不真正关心托管记忆,你不应该期望Dispose
实际上会被召唤 - 它不是必须的。 唯一被运行时调用的是终结器,你只能使用它来处理本机资源 - 实际上,你不能保证你拥有的对象终结器运行时仍然存在的引用 - 当时可能已经回收了托管内存。这就是永远在终结器中处理托管资源的原因。
所以是的,她完全正确。关键是IDisposable
与垃圾收集器无关。处置并不意味着收集垃圾。
答案 1 :(得分:12)
她对钱using
的说法是正确的,只是try/finally{obj.Dispose();}
的合成糖。 using
语句确保将丢弃该对象。(将调用Dispose方法)但它与垃圾收集无关。
看看这个Understanding-the-using-statement
简短回答:所以现在我们知道using语句只是调用Dispose
并且除此之外什么都不做,请记住Dispose
方法并不比任何其他方法特别。这只是一种方法,而且就是这样。所以它与垃圾收集无关。有趣的是"垃圾收集器"甚至不了解Dispose
方法或IDisposable
。
希望这有帮助