为什么 Dispose() 应该处理托管资源而不是终结器?
Why should Dispose() dispose managed resources and finalizer not?
我们都知道 System.IDisposable 模式。它被描述了无数次,也在 Whosebug 上:
link: Dispose() for cleaning up managed resources?
The Disposable patterns advises that I should only dispose managed resources if my object is being disposed, not during finalize
您可以看到出现这种情况是因为建议使用以下代码:
protected void Dispose(bool disposing)
{
if (disposing)
{
// Code to dispose the managed resources of the class
}
// Code to dispose the un-managed resources of the class
}
我知道只要我的 class 有一个实现 System.IDisposable 的(私有)成员,我的 class 就应该实现 System.IDisposable。如果布尔值处理为真,则 Dispose(bool) 应调用私有成员的 Dispose()。
如果在完成过程中调用 Dispose 为什么会出现问题?那么,如果在 finalize 期间调用以下 Dispose,为什么会出现问题?
protected void Dispose(bool disposing)
{
if (myDisposableObject != null)
{
myDisposableObject.Dispose();
myDisposableObject = null;
}
}
一般来说,您应该尽快摆脱资源。如果您不需要资源,为什么要保留它以浪费内存?
此外,为了在终结期间调用 Dispose(),您必须为您的对象创建终结器,即 C# 中的析构函数。然而,调用对象的终结器的确切时间是不确定的,这意味着您的托管对象在那一刻可能不再存在/无法安全访问。即使是执行终结器的线程也是不确定的,这也可能导致难以预见的问题。
出于这些原因,应创建终结器以仅释放非托管资源。
很少有程序员了解 'fully' 终结的工作原理。例如,垃圾收集器在对象实例化期间识别出您的类型具有终结器,并将您的实例放入称为 finalizequeue 的特殊内部数据结构中。实际上,当您使用 sos.dll (windbg) 调试您的应用程序时,您可以使用命令 !finalizeQueue 来显示具有终结器并且在稍后的某个时间点尚未完成的对象。
当对象的终结器 运行s 时,以下情况之一将适用于它可能持有的几乎所有 IDisposable
对象:
它持有对另一个对象的唯一引用,并且另一个对象的终结器已经 运行,所以不需要对它做任何事情。
它持有对那个其他对象的唯一引用,并且那个其他对象的终结器被安排到 运行,即使它还没有,也不需要做任何事情它.
其他对象还在使用IDisposable
对象,这种情况下终结器一定不能调用Dispose
.
另一个对象的 Dispose
方法不能安全地 运行 来自终结器线程上下文(或者,更一般地说,除了创建对象的线程上下文之外的任何线程上下文), 在这种情况下终结器不能调用 Dispose
.
即使在上述 none 应用的情况下,除了实现 IDisposable
的事实之外,知道的代码可能会了解很多关于其清理要求的代码,并且应该经常使用更详细的清理协议。
我们都知道 System.IDisposable 模式。它被描述了无数次,也在 Whosebug 上:
link: Dispose() for cleaning up managed resources?
The Disposable patterns advises that I should only dispose managed resources if my object is being disposed, not during finalize
您可以看到出现这种情况是因为建议使用以下代码:
protected void Dispose(bool disposing)
{
if (disposing)
{
// Code to dispose the managed resources of the class
}
// Code to dispose the un-managed resources of the class
}
我知道只要我的 class 有一个实现 System.IDisposable 的(私有)成员,我的 class 就应该实现 System.IDisposable。如果布尔值处理为真,则 Dispose(bool) 应调用私有成员的 Dispose()。
如果在完成过程中调用 Dispose 为什么会出现问题?那么,如果在 finalize 期间调用以下 Dispose,为什么会出现问题?
protected void Dispose(bool disposing)
{
if (myDisposableObject != null)
{
myDisposableObject.Dispose();
myDisposableObject = null;
}
}
一般来说,您应该尽快摆脱资源。如果您不需要资源,为什么要保留它以浪费内存?
此外,为了在终结期间调用 Dispose(),您必须为您的对象创建终结器,即 C# 中的析构函数。然而,调用对象的终结器的确切时间是不确定的,这意味着您的托管对象在那一刻可能不再存在/无法安全访问。即使是执行终结器的线程也是不确定的,这也可能导致难以预见的问题。
出于这些原因,应创建终结器以仅释放非托管资源。
很少有程序员了解 'fully' 终结的工作原理。例如,垃圾收集器在对象实例化期间识别出您的类型具有终结器,并将您的实例放入称为 finalizequeue 的特殊内部数据结构中。实际上,当您使用 sos.dll (windbg) 调试您的应用程序时,您可以使用命令 !finalizeQueue 来显示具有终结器并且在稍后的某个时间点尚未完成的对象。
当对象的终结器 运行s 时,以下情况之一将适用于它可能持有的几乎所有 IDisposable
对象:
它持有对另一个对象的唯一引用,并且另一个对象的终结器已经 运行,所以不需要对它做任何事情。
它持有对那个其他对象的唯一引用,并且那个其他对象的终结器被安排到 运行,即使它还没有,也不需要做任何事情它.
其他对象还在使用
IDisposable
对象,这种情况下终结器一定不能调用Dispose
.另一个对象的
Dispose
方法不能安全地 运行 来自终结器线程上下文(或者,更一般地说,除了创建对象的线程上下文之外的任何线程上下文), 在这种情况下终结器不能调用Dispose
.
即使在上述 none 应用的情况下,除了实现 IDisposable
的事实之外,知道的代码可能会了解很多关于其清理要求的代码,并且应该经常使用更详细的清理协议。