我有以下代码:
public void Dispose()
{
if (_instance != null)
{
_instance = null;
// Call GC.SupressFinalize to take this object off the finalization
// queue and prevent finalization code for this object from
// executing a second time.
GC.SuppressFinalize(this);
}
}尽管有一个注释解释了与GC相关的调用的目的,但我仍然不明白它为什么会出现在那里。
当所有实例都不存在时,对象不是注定要进行垃圾回收吗?比如,当在using块中使用时?
这将发挥重要作用的用例场景是什么?
发布于 2010-06-14 23:42:43
在实现dispose模式时,还可以向调用Dispose()的类添加终结器。这是为了确保Dispose()总是被调用,即使客户端忘记调用它。
为了防止dispose方法运行两次(如果对象已经被释放),需要添加GC.SuppressFinalize(this);。该文档提供了一个sample
class MyResource : IDisposable
{
[...]
// This destructor will run only if the Dispose method
// does not get called.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
resource.Cleanup()
}
disposed = true;
}
}发布于 2010-06-15 00:30:05
垃圾收集:当对象不再被引用时,GC将回收该对象所使用的内存。
Dispose:来自IDisposable接口的方法,当程序员调用它(直接或通过using块间接调用)时,它将释放所有托管和非托管资源。
终结器:释放所有非托管资源的方法。在回收内存之前由GC调用。
托管资源:实现IDisposable接口的任何.NET类,如Streams和DbConnections。
非托管资源:包装在托管资源类中的填充。Windows句柄是最简单的例子。
现在回答你的问题:
GC保存了所有对象的列表(终结化队列),这些对象的类声明了终结器(在C#中是~ClassName)。对象在创建时被放入此队列中。GC定期运行以检查是否有任何对象无法从程序中访问。然后,它检查是否有任何不可访问的对象从Finalization队列中被引用,并将这些对象放入另一个称为Freacheable队列的队列中,而其余的则被回收。一个单独的线程用于运行Freacheable队列中对象的Finalize方法。
下次GC运行时,它会发现之前在Freacheable队列中的一些对象已经完成,因此准备回收。请注意,GC至少需要两个周期(如果有很多终结器要做,则需要更多的周期)才能使用终结器来清除对象,这会导致一些性能损失。
SuppressFinalize方法只是在object头中设置一个标志,该标志指示终结器不必运行。这样,GC就可以立即回收对象的内存。根据上面的定义,Dispose方法与Finalizer做同样的事情(甚至更多),所以如果它被执行了,那么Finalization就不再是必要的了。使用SuppressFinalize方法,您可以通知GC这一事实,从而为GC节省一些工作。此外,现在您不必在终结器中实现检查,以避免双重释放。Dispose的唯一问题是不能保证运行,因为调用它是程序员的责任,这就是为什么有时我们需要麻烦终结器的原因。
也就是说,您很少需要编写终结器,因为对于大多数常见的非托管资源,托管包装器已经存在,并且托管资源将通过从您自己的Dispose方法调用它们的Dispose方法来释放,并且只能从那里!在终结器中,决不能调用Dispose方法。
进一步阅读
发布于 2010-06-14 23:46:12
可以最终确定的对象在第一次GC运行后仍然存在。
通常,当GC检测到某个对象不可访问时,它会回收该对象。如果对象是可终结化的,那么GC不会回收它;相反,它仍然认为它是可到达的(以及该对象引用的所有对象,等等),并安排它进行终结化。仅当在完成后的某一时刻再次发现对象不可访问时,才会回收该对象。
这意味着可finalizable对象会产生额外的成本:该对象必须在内存中保留更长时间。因此,你会看到这样的调用:在不需要的时候取消finalization是值得的。在这里,对象使用finalization来确保它总是在某个时刻被“处理”。当它被显式处理时,它不再需要被最终确定。
https://stackoverflow.com/questions/3038571
复制相似问题