为了账号安全,请及时绑定邮箱和手机立即绑定

C# 中的“处置模式”:为什么我们需要“if(处置)”条件?

C# 中的“处置模式”:为什么我们需要“if(处置)”条件?

C#
慕妹3146593 2022-12-04 13:04:03
因此,默认的处置模式实现如下所示:class SomeClass : IDisposable{   // Flag: Has Dispose already been called?   bool disposed = false;   // Public implementation of Dispose pattern callable by consumers.   public void Dispose()   {       Dispose(true);      GC.SuppressFinalize(this);              }   // Protected implementation of Dispose pattern.   protected virtual void Dispose(bool disposing)   {      if (disposed)         return;       if (disposing) {         // Free any other managed objects here.      }      // Free any unmanaged objects here.      disposed = true;   }   ~SomeClass()   {      Dispose(false);   }}据说:如果方法调用来自终结器(即,如果处置是 false),则仅执行释放非托管资源的代码。由于未定义垃圾收集器在终结期间销毁托管对象的顺序,因此Dispose使用值调用此重载false可防止终结器尝试释放可能已被回收的托管资源。问题是:为什么假设被 object of 引用的对象SomeClass可能已经被释放,我们不应该在从 finalizer 调用方法时尝试释放它们?如果那些对象仍然被我们的SomeClass对象引用,它们就不能被释放,不是吗?据说:那些有挂起(未运行)终结器的(暂时)保持活动状态,并被放入一个特殊的队列中。[...] 在每个对象的终结器运行之前,它仍然非常活跃——该队列充当根 对象。因此,我们的SomeClass对象再次被该队列引用(这与被根引用相同)。对象引用的其他对象SomeClass也应该是活动的(因为它们是通过SomeClass对象生根的)。那么为什么以及如何在SomeClass调用终结器时释放它们呢?
查看完整描述

2 回答

?
慕斯王

TA贡献1864条经验 获得超2个赞

Konrad Kokosa 在他的《Pro .NET Memory Management 》一书中有一个令人印象深刻的解释。(强调)

在 GC 期间,在标记阶段结束时,GC 检查终结队列以查看是否有任何可终结对象已死亡。如果它们是一些,它们还不能被删除,因为它们的终结器需要被执行。因此,这样的对象被移动到另一个名为 fReachable queue 的队列。它的名字来自于它代表最终化可达对象的事实——那些现在只因为最终化才可达的对象。如果找到任何此类对象,GC 会向专用终结器线程指示有工作要做。

终结线程是由 .NET 运行时创建的另一个线程。它从 fReachable 队列中一个一个地移除对象并调用它们的终结器。这发生在 GC 恢复托管线程之后,因为终结器代码可能需要分配对象。由于此对象的唯一根已从 fReachable 队列中删除,下一次谴责此对象所在世代的 GC 将发现它不可访问并回收它。

此外,fReachable 队列在 Mark 阶段被视为根,因为终结器线程可能不够快,无法在 GC 之间处理来自它的所有对象。这使可终结对象更多地暴露于中年危机——它们可能会停留在 fReachable 队列中一段时间,仅仅因为等待终结而消耗第 2 代。

我认为这里的关键是:

fReachable 队列在 Mark 阶段被视为根,因为终结器线程可能不够快,无法在 GC 之间处理来自它的所有对象。


查看完整回答
反对 回复 2022-12-04
?
慕的地10843

TA贡献1785条经验 获得超8个赞

.NET 中的对象在存在对它们的任何引用时就存在。一旦最后一个引用不存在,它们就会不复存在。当对象存在时,对象使用的存储将永远不会被回收,但是 GC 在回收存储之前会做几件事:

  1. 有一个特殊的列表,称为“终结器队列”,它包含对所有已注册终结器的对象的引用。在识别出 Universe 中任何地方存在的所有其他引用之后,GC 将检查终结器队列中的所有对象,以查看是否找到了对它们的任何引用。如果此过程导致它找到以前未发现的对象,它会将引用复制到另一个称为“freachable 队列”的列表。任何时候 freachable 队列非空并且没有终结器正在运行,系统将从该队列中提取一个引用并调用终结器。

  2. GC 还将检查所有弱引用的目标,并使目标未被任何有效强引用识别的任何弱引用无效。

请注意,finalize 方法不会“垃圾收集”对象。相反,它会延长对象的存在直到finalize被调用,目的是允许它履行对外部实体可能具有的任何义务。如果那时在宇宙中任何地方都不存在对该对象的引用,则该对象将不复存在。

请注意,两个具有终结器的对象可能会相互引用。在这种情况下,它们的终结器运行的顺序是未指定的。


查看完整回答
反对 回复 2022-12-04
  • 2 回答
  • 0 关注
  • 68 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信