是的,我知道如何使用GC.SuppressFinalize()
-这里有解释。我读过很多次使用GC.SuppressFinalize()
从终结队列中删除对象,并且认为这很好,因为它使 GC 从调用终结器的额外工作中解脱出来。
所以我制作了这个(主要是无用的)代码,类IDisposable
在链接到答案中实现:
public class MyClass : IDisposable
{
~MyClass()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
System.Threading.Thread.Sleep(0);
disposed = true;
}
}
}
这里我Sleep(0)
用来模仿一些简短的非托管工作。请注意,由于类中的布尔字段,此非托管工作永远不会执行超过一次 - 即使我Dispose()
多次调用或者如果对象首先被释放然后完成 - 在任何这些情况下,“非托管工作”只执行一次.
这是我用于测量的代码:
var start = DateTime.UtcNow;
var objs = new List<Object>();
for (int i = 0; i < 1000 * 1000 * 10; i++)
{
using (var obj = new MyClass())
{
objs.Add(obj);
}
}
objs = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
var duration = (DateTime.UtcNow - start).TotalMilliseconds;
Console.WriteLine(duration.ToString());
是的,我将刚刚处理的对象添加到List
.
所以我运行上面的代码,它在 12.01 秒内运行(发布,没有调试器)。然后我注释掉GC.SuppressFinalize()
调用并再次运行代码,它在 13.99 秒内运行。
调用的代码GC.SuppressFinalize()
快了 14.1%。即使在这种荒谬的情况下,所有事情都是为了给 GC 施加压力(你很少用终结器连续制作一千万个对象,不是吗?)差异大约是 14%。
我猜在现实场景中,只有一小部分对象首先具有终结器,并且这些对象也没有大量创建,因此整体系统性能的差异可以忽略不计。
我错过了什么吗?是否有一个现实的场景,我会看到使用 的显着好处GC.SuppressFinalize()
?