假设如下:
IDisposable。sealed --类不能从非托管资源派生和添加非托管资源。using语句中使用--即在完成时调用Dispose()。这个类有3种可能的IDisposable实现:
Dispose成员上的Dispose()的最小IDisposable方法--无终结器。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);
}发布于 2015-03-19 16:40:44
不同版本的.NET GC可能会做不同的事情,但据我所知,任何具有Finalize方法的对象都将被添加到“终结器队列”(如果放弃请求通知的对象列表),并且只要它存在就会留在队列中。取消注册和重新注册以便最后完成的方法( IMHO应该是Object的受保护成员)在对象标头中设置或清除一个标志,该标志控制对象是否应该移动到“可自由队列”( finalize方法应该在实际情况下立即运行的对象列表),但不会导致对象被添加或从终结器队列中删除。
因此,覆盖Finalize的每一种类型的每个实例都会对它所参与的每个垃圾回收周期(只要它存在)施加一小部分但非零的开销。在放弃对象之前在对象上调用SuppressFinalize将防止它被移动到可自由的队列,但不会消除由于它在整个存在过程中一直处于可终结队列而造成的开销。
我建议任何面向公共的对象都不应该实现Finalize。Finalize方法有一些合法的用法,但是覆盖它的类应该避免保存对任何不需要终结的引用(有些烦人的是,如果可终结的对象持有对弱引用的唯一引用,弱引用可能在终结器运行之前失效,即使弱引用的目标仍然活着)。
发布于 2015-03-19 10:53:37
您应该只在需要清理非托管资源的对象上包含终结器。因为您只有托管成员,所以不需要终结器--如果成员本身有终结器,并且不为它们调用GC.SuppressFinalize(),则终结器将在它们上运行。
终结器的目标是在GC喜欢的时候清理非托管资源及其托管包装器,而Dispose模式的目标是在特定时刻清理任何类型的资源。
没有人应该认为“我通过调用SuppressFinalize来避免终结器开销”--相反,他们应该认为“我清理了我的非托管资源,没有必要运行终结器”。
关于编号问题:
发布于 2019-04-25 14:53:44
有时,我会使用终结器进行调试,以检查是否在某个地方丢失了一些dispose。如果有人感兴趣,我对我的系统进行了快速测试,以检查性能影响(Windows10,.Net 4.7.1,IntelCorei5-8250U)。
添加终结器并抑制它的成本大约为每对象60 ns /,而添加它和忘记调用dispose的成本大约为每对象 800 ns。性能影响与调试/发布版本以及/不附加调试器非常一致,这可能是因为垃圾收集器在这两个版本中都是相同的。
添加终结器并抑制它的性能影响是最小的,除非您正在构造大量的这些对象,这通常不是这样的。甚至微软自己的Task也使用终结器(几乎总是被禁止的),而且这个类非常轻量级和性能良好。所以他们显然同意。
然而,让终结器运行可能会变得非常糟糕。考虑到我的测试用例使用了一个没有引用对象的琐碎类,而且它已经慢了一个数量级。拥有大量的引用对象应该花费更多的时间,因为所有这些对象都需要在额外的世代中保持存活。这也会导致大量复制在垃圾收集的压缩阶段发生。
测试的源代码:
using System;
using System.Diagnostics;
namespace ConsoleExperiments
{
internal class Program
{
private static void Main(string[] args)
{
GenerateGarbageNondisposable();
GenerateGarbage();
GenerateGarbageWithFinalizers();
GenerateGarbageFinalizing();
var sw = new Stopwatch();
const int garbageCount = 100_000_000;
for (var repeats = 0; repeats < 4; ++repeats)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
sw.Restart();
for (var i = 0; i < garbageCount; ++i)
GenerateGarbageNondisposable();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine("Non-disposable: " + sw.ElapsedMilliseconds.ToString());
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
sw.Restart();
for (var i = 0; i < garbageCount; ++i)
GenerateGarbage();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine("Without finalizers: " + sw.ElapsedMilliseconds.ToString());
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
sw.Restart();
for (var i = 0; i < garbageCount; ++i)
GenerateGarbageWithFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine("Suppressed: " + sw.ElapsedMilliseconds.ToString());
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
sw.Restart();
for (var i = 0; i < garbageCount; ++i)
GenerateGarbageFinalizing();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine("Finalizing: " + sw.ElapsedMilliseconds.ToString());
Console.WriteLine();
}
Console.ReadLine();
}
private static void GenerateGarbageNondisposable()
{
var bla = new NondisposableClass();
}
private static void GenerateGarbage()
{
var bla = new UnfinalizedClass();
bla.Dispose();
}
private static void GenerateGarbageWithFinalizers()
{
var bla = new FinalizedClass();
bla.Dispose();
}
private static void GenerateGarbageFinalizing()
{
var bla = new FinalizedClass();
}
private class NondisposableClass
{
private bool disposedValue = false;
}
private class UnfinalizedClass : IDisposable
{
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
private class FinalizedClass : IDisposable
{
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
}
disposedValue = true;
}
}
~FinalizedClass()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
}https://stackoverflow.com/questions/29140628
复制相似问题