GC.SupressFinalizer() 是否会阻止 GC 收集托管资源?
Does GC.SupressFinalizer() prevent GC from collecting the managed resources?
如果终结器(析构函数)在 class 中实现,并且从覆盖的 Dispose() 方法调用 GC.SupressFinalizer(),垃圾收集器仍会处理任何托管资源的实例class 可能有?
令我困惑的是微软关于此事的文档。例如,虚拟 Dispose 方法中 IDisposable 模式的 implemenation 负责托管资源和非托管资源。如果 GC 默认处理托管资源,为什么要这样做?
如果我这样定义 class:
public class Car
{
string plateNum;
}
并将此类型用作 class 中的一个文件,根据 Microsoft 的文档,该文件还处理非托管资源,处理对象处置的正确方法是调用 Car 上的 Dispose以及。为此,Car 必须实现 IDisposable 接口。 Car 只处理托管资源,没有理由在 Car class 中这样做,我不知道 Dispose() 甚至会在那里做什么,也许给 plateNum 空值?另外,为什么有人想在仅处理托管资源的 class 上实现 IDisposable?
考虑到这一点,为什么在虚拟 Dispose() 方法的代码中有一个部分(在 MS 文档中的示例中)其中 managed 资源被处置?
protected virtual 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.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
我能想到的唯一原因是 GC.SupressFinalize(Object) 告诉 GC 它不需要处理与给定的对象参数相关的任何事情。 但是不应该是这种情况,因为实现终结器应该只意味着实现它的对象应该只放在终结器队列中 after该对象已被 GC 处理,因为应调用由用户显式实现的 Finalizer 方法。
此外,如果定义了终结器,这是否会改变 GC 收集实例包含的托管资源的方式,还是仅意味着将执行终结器中包含的其他代码?
SO 上已经有很多关于此的问答,所以我会给你一个非常实用的答案:你 won't ever need to write a finalizer.
总结:在极少数情况下,您拥有非托管资源,请使用 SafeHandle class 使其成为托管资源。
当您仔细检查完整模式时,您会发现在没有非托管资源的情况下,析构函数(又名终结器,~MyClass() {}
)代码路径什么都不做。
实际上,没有 SuppressFinalize() 的终结器非常昂贵,它会将对象的清理延迟到下一个 GC。将其数据提升到第 1 代。
具有 virtual void Dispose(bool)
的完整模式的其余原因是继承。拥有 class 的资源几乎永远不需要它。所以把它密封起来,你所需要的(想要的)是:
public sealed MyClass : IDisposable
{
private SomeResource _myResource;
public void Dispose()
{
_myResource?.Dispose();
}
}
当您需要继承时,这就是 the official pattern。
如果终结器(析构函数)在 class 中实现,并且从覆盖的 Dispose() 方法调用 GC.SupressFinalizer(),垃圾收集器仍会处理任何托管资源的实例class 可能有? 令我困惑的是微软关于此事的文档。例如,虚拟 Dispose 方法中 IDisposable 模式的 implemenation 负责托管资源和非托管资源。如果 GC 默认处理托管资源,为什么要这样做? 如果我这样定义 class:
public class Car
{
string plateNum;
}
并将此类型用作 class 中的一个文件,根据 Microsoft 的文档,该文件还处理非托管资源,处理对象处置的正确方法是调用 Car 上的 Dispose以及。为此,Car 必须实现 IDisposable 接口。 Car 只处理托管资源,没有理由在 Car class 中这样做,我不知道 Dispose() 甚至会在那里做什么,也许给 plateNum 空值?另外,为什么有人想在仅处理托管资源的 class 上实现 IDisposable? 考虑到这一点,为什么在虚拟 Dispose() 方法的代码中有一个部分(在 MS 文档中的示例中)其中 managed 资源被处置?
protected virtual 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.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
我能想到的唯一原因是 GC.SupressFinalize(Object) 告诉 GC 它不需要处理与给定的对象参数相关的任何事情。 但是不应该是这种情况,因为实现终结器应该只意味着实现它的对象应该只放在终结器队列中 after该对象已被 GC 处理,因为应调用由用户显式实现的 Finalizer 方法。 此外,如果定义了终结器,这是否会改变 GC 收集实例包含的托管资源的方式,还是仅意味着将执行终结器中包含的其他代码?
SO 上已经有很多关于此的问答,所以我会给你一个非常实用的答案:你 won't ever need to write a finalizer.
总结:在极少数情况下,您拥有非托管资源,请使用 SafeHandle class 使其成为托管资源。
当您仔细检查完整模式时,您会发现在没有非托管资源的情况下,析构函数(又名终结器,~MyClass() {}
)代码路径什么都不做。
实际上,没有 SuppressFinalize() 的终结器非常昂贵,它会将对象的清理延迟到下一个 GC。将其数据提升到第 1 代。
具有 virtual void Dispose(bool)
的完整模式的其余原因是继承。拥有 class 的资源几乎永远不需要它。所以把它密封起来,你所需要的(想要的)是:
public sealed MyClass : IDisposable
{
private SomeResource _myResource;
public void Dispose()
{
_myResource?.Dispose();
}
}
当您需要继承时,这就是 the official pattern。