是的,我知道 如何使用GC.SuppressFinalize()
- 它解释了here。我多次读过使用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()
或者对象首先处理然后最终确定 - 在任何这些情况下,&#34 ;非管理工作"只执行一次。
这是我用于测量的代码:
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()
?
答案 0 :(得分:6)
举一个简单的例子:
protected virtual void Dispose(bool disposing)
{
if(!disposing)
{
HardStopSystem(
$"Critical failure: an instance of '{GetType().Name}' was not disposed");
}
}
只有在击中终结器时才会达到此目的。是的,它是强制性的和人为的,但是:这是基于我在许多系统中看到的真实代码,其中至关重要,事情被正确处理。
另一个例子包括确保非托管指针之类的东西不会被释放两次(这会失败)。现在是的,你可以设置一个标记来说“不再这样做”,但是你会进入不可变类型的主题等。
整体系统性能的差异可以忽略不计。
这在很大程度上取决于场景。最终,终结者更多的是正确性而不是表现。 IDisposable
与绩效更相关,因为它与及时性有关。