如果一个对象已经被释放,那么抑制gc终结器是否可以节省一些时间

本文关键字:是否 时间 节省 gc 一个对象 释放 如果 | 更新日期: 2023-09-27 18:28:15

垃圾回收可能会成为一个耗时的过程。在这方面,GC往往只有在必要的时候才能工作。如果一个对象已经被释放,为了节省时间和帮助GC,GC的终结器应该被抑制吗?

using(var sO = new someObject())
{
 //work with object
}
public class someObject : IDisposable
{
  internal Stream someResource;
  internal Context someContext;
  public void Dispose()
  {
   someContext.Dispose();
   someResource.Dispose();
   //A: does suppressing the GC finalizer here save time for the GC?
   //B: can this cause memory leaks?
   //GC.SuppressFinalize(this);
  }
}

如果一个对象已经被释放,那么抑制gc终结器是否可以节省一些时间

为了消除一些混乱:

  • 如果需要以某种特殊方式清理非托管资源,则只需要一个终结器。

  • 如果没有非托管资源,那么就不需要终结器。

  • 如果您有一个终结器,那么您肯定应该实现IDisposable。

  • 如果你有一个终结器,那么你应该在Dispose中调用GC.SuppressFinalize,因为如果你自己已经清理过了,就不需要调用终结器。

  • 如果您有终结器,则只需要调用GC.SuppressFinalize。如果你不这样做,你可能仍然想把它称为一种防御措施。

在这里抑制GC终结器是否为GC节省时间?

如果存在非托管资源,并且您的对象具有终结器,则为yes;如果不取消显示,您的对象可能会在最终确定队列中存活很长时间。您处理的资源也可能需要很长时间才能完成(例如,关闭昂贵的I/O通道)。

如果你没有终结器,你就是说你没有任何未管理的东西要清理。您仍然应该调用SuppressFinalize作为防御措施。

根据FxCop规则:

"无法抑制终结会降低性能,而且不会带来任何好处。"


对于您的另一个问题,

这会导致内存泄漏吗?

在本例中,如果有任何资源未被管理,则为yes。如果您的对象在有机会调用Dispose之前以某种不寻常的方式终止,则非托管资源将无法正确释放。例如,在使用someObject实例时,如果someResource处于非托管状态并引发异常,会发生什么情况。

如果您的对象持有非托管资源,并且您需要确保这些资源被清理,那么您也需要一个终结器(在您的情况下,它将被命名为~someObject)。

如果您主动Dispose一个对象,那么是的,您应该取消终结。如果您主动/果断地释放所有资源,就不需要最终确定对象。让它挂在终结器上只是在以后浪费时间。

有一点还没有提到:只有当代码可能需要通过某个执行路径访问对象的字段或对象标头(一种数据结构,包含有关对象类型的信息,是否用作监视锁等)时,对象才需要被视为"活动"。如果对象字段包含非托管句柄,而Dispose方法所做的最后一件事是关闭句柄,当Dispose方法运行时,对象可能有资格完成。哎呀。对GC.SuppressFinalize的调用不仅可以防止终结器在执行后入队;其作为CCD_ 9所做的最后一件事的放置将防止对象在执行之前变得有资格完成