在Dispose中使用/不使用SuppressFinalize
假设如下:
IDisposable
。 sealed
- 一个类不能派生并添加非托管资源。 using
语句中using
- 即完成时调用Dispose()
。 这个类有3种可能的IDisposable
实现:
IDisposable
成员上调用Dispose()
最小Dispose
方法 - 无终结器 。 IDisposable
实现但缺少 Dispose()
通常的GC.SuppressFinalize(this)
调用。 IDisposable
实现(以及Dispose()
GC.SuppressFinalize(this)
调用)。 以下声明是否正确? 我对此有正确的理解吗?
SuppressFinalize
,所以终结器将不会运行。 这种情况仍然导致进入终结器队列的对象的小开销,但终结器并不实际运行。 关键的一点是,想到“我通过调用SuppressFinalize
避免了终结器开销” - 但我认为( 并且想澄清 )这是不正确的。 在终结器队列中的对象的开销仍然产生 - 你所要避免的是实际的终结器调用 - 在一般情况下,这只是“我已经处置无用”了。
注意:这里的“完全标准的IDisposable
实现”是指设计用于涵盖非托管资源和管理资源的标准实现(注意这里我们只有托管对象成员)。
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
private bool _disposed;
protected virtual void Dispose(bool disposing) {
if (_disposed)
return;
if (disposing) {
// dispose managed members...
}
_disposed = true;
}
~AXCProcessingInputs() {
Dispose(false);
}
不同版本的.NET GC可能会做不同的事情,但根据我的理解,任何具有Finalize
方法的对象都将添加到“终结器队列”(已放弃请求通知的对象列表)中,并将保留在该队列中只要它存在。 注销和重注册以完成定义的方法(其中,IMHO应该是Object
成员)设置或清除对象头中的一个标志,该标志控制对象是否应移动到“可排队队列”( finalize
方法应该如果发现它被放弃,但不会导致对象被添加或从终结器队列中移除。
每个覆盖Finalize
类型的每个实例都会因此对它所参与的每个垃圾收集周期施加一个小但非零的开销,只要它存在。 在放弃它之前调用对象的SuppressFinalize
可以防止它被移动到可放入队列中,但不会消除由于它在整个存在期间一直处于可终止队列而导致的开销。
我会建议没有面向公众的对象应该实施Finalize
。 Finalize
方法有一些合法的用法,但是覆盖它的类应该避免保存对最终化不需要的任何东西的引用(有点令人讨厌的是,如果可终结对象只包含对弱引用的引用,那么弱引用可能会在终结器之前失效即使弱参考的目标仍然存在)。
您只应在需要清理非托管资源的对象上包含终结器。 由于您只有托管成员,因此您不需要终结器 - 终结器将在成员自身上运行(如果它们具有终结器),并且GC.SuppressFinalize()
未被调用。
终结器的目标是每当GC感觉到它时清理非托管资源及其托管包装,而Dispose
模式的目标是在特定时刻清理任何类型的资源。
没有人会认为“我通过调用SuppressFinalize避免了终结器的开销” - 相反,他们应该认为“我已经清理了我的非托管资源,没有必要运行终结器”。
关于编号问题:
Dispose()
上一篇: with/without SuppressFinalize in Dispose
下一篇: mark methods as safe