Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# GC是否需要多次收集具有挂起终结器的对象?_C#_Garbage Collection_Finalizer - Fatal编程技术网

C# GC是否需要多次收集具有挂起终结器的对象?

C# GC是否需要多次收集具有挂起终结器的对象?,c#,garbage-collection,finalizer,C#,Garbage Collection,Finalizer,简而言之,我正在阅读C#8.0书中的“处理和垃圾收集”一章。说到终结器,它说: GC识别要删除的未使用对象,这些对象没有 终结器将立即删除,具有待定终结器的终结器将被删除 保持活动状态并放入特殊队列。当垃圾 集合已完成,并且您的程序继续执行 终结器线程然后开始与程序并行运行, 从特殊队列中拾取对象并运行其终结 方法 本段是否意味着GC需要再次收集等待最终确定的对象?我假设它已经被GC检测为垃圾,为什么在再次完成后需要收集它?GC通过从GC根遍历对象图来工作。当GC执行集合时,它会检查没有引用的对

简而言之,我正在阅读C#8.0书中的“处理和垃圾收集”一章。说到终结器,它说:

GC识别要删除的未使用对象,这些对象没有 终结器将立即删除,具有待定终结器的终结器将被删除 保持活动状态并放入特殊队列。当垃圾 集合已完成,并且您的程序继续执行 终结器线程然后开始与程序并行运行, 从特殊队列中拾取对象并运行其终结 方法


本段是否意味着GC需要再次收集等待最终确定的对象?我假设它已经被GC检测为垃圾,为什么在再次完成后需要收集它?

GC通过从GC根遍历对象图来工作。当GC执行集合时,它会检查没有引用的对象(因此可以安全地释放)

终结器延迟对象的垃圾收集

为什么??GC认为对象可以安全地释放(不连接到GC根)。但是,如果终结器尚未运行,则无法释放内存

因此GC将对象标记为具有挂起的终结器,并且在第一次传递时不会释放该空间。GC也不会在该时刻运行终结器(它将其放入“挂起的终结器”队列)

这就是为什么除非必要,否则使用终结器是不好的做法。它会延迟收集。有些人错误地认为GC在收集过程中运行终结器。事实并非如此

什么时候有必要?一个好的经验法则是,如果对象引用非托管内存(GC不处理),那么您绝对应该使用终结器来避免内存泄漏。如果只引用托管对象,则不要引用


如果您确实实现了终结器,我还将实现
IDisposable
,释放
Dispose
上的所有非托管资源,并停止终结器与一起运行。

嗯,对象不是第一次“收集”的。它们被视为需要额外的处理(需要运行终结器代码),并放入终结队列,以便可以单独处理它们。这最终将它们放在“freachable”队列中,该队列现在已经恢复了对象:它现在被freachable队列引用,不再符合收集条件。在终结器实际执行并且对象从freachable队列中移除后,它将不可访问

(这就是它过去的工作方式,不确定在较新的.NET版本中是否发生了变化,但我不知道有任何变化。)


因此,如果通过“收集”我们了解到内存被回收,那么对象实际上不会多次“收集”。但是,它确实需要额外的处理,并将在稍后由GC重新评估。

如果您确实有一个管理非托管资源(不仅仅是内存)的类,并且您确实有一个终结器,则添加到最后一段,确保您的
Dispose
方法主动释放这些资源,然后将对象标记为不再需要终结器(
GC.supersfinalization
)。这样,该对象就不再需要GC进行特殊处理,并且可以像任何其他对象一样进行收集。我非常确定C#不使用引用计数。这个术语甚至不适合您的回答,因为您描述的是遍历垃圾收集器的逻辑,即对象是否可以从根访问。@霍尔格遍历对象图是肯定的。但这实际上是引用计数。我没说用内部计数器什么的。具体来说,GC想知道引用计数是否为零。这是一个实现细节,真的。功能等同。不,是一个具有特定含义的既定术语。对于未来的读者来说,以不同于世界其他地方的方式使用一个技术术语是没有帮助的。。。我猜你的书指出了.NETGC是一代垃圾收集器。第0代收藏便宜,第1代便宜得多,第2代非常昂贵。如果对象被最终确定,它将失去收集Gen0的机会(因为它只能在最终确定器运行后被收集)。确保对象在正确使用时不需要终结的另一个原因这些术语没有严格的定义。通常,术语“收集”指的是识别可访问对象和不可访问对象的行为,而“回收”指的是允许重用对象的内存。在这方面,带有终结器的对象将被收集两次。然而,通常情况下,垃圾收集器不会处理无法访问的对象,而是将幸存者移动到新的内存位置,这也必须对可终结的对象执行,可以公平地说,实际上这些对象根本没有被收集。