我有时会出于调试目的使用终结器,以检查我是否在某处遗漏了一些处置。如果有人感兴趣,我对我的系统进行了快速测试以检查性能影响(Windows 10、.Net 4.7.1、Intel Core i5-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);
}
}
}
}