好的,众所周知,当 GC 将对象识别为垃圾时,它会隐式调用对象上的 Finalize
方法。但是如果我执行 GC.Collect()
会发生什么? finalizer 是否仍然执行?有人问我这个问题,我回答"is",然后我想:“完全正确吗?”
最佳答案
Ok, it's known that GC implicitly calls Finalize methods on objects when it identifies that object as garbage.
不不不。这不是已知,因为要成为知识,一个陈述必须是真。该声明是错误的。 垃圾收集器在跟踪时不会运行终结器,无论它是自己运行还是调用 Collect
。 终结器线程在跟踪收集器找到垃圾后运行终结器,并且相对于对 Collect
的调用,这发生异步。 (如果它真的发生了,它可能不会发生,正如另一个答案所指出的那样。)也就是说,您不能依赖在控制从 Collect
返回之前执行的终结器线程。
这是它如何工作的一个过于简单的草图:
- 当收集发生时,垃圾收集器跟踪线程跟踪根源——已知存在的对象,以及它们引用的每个对象,等等——以确定死对象。
- 具有未决终结器的“死”对象被移动到终结器队列中。 终结器队列是根。因此,那些“死”的对象实际上还活着。
- 终结器线程(通常与 GC 跟踪线程不同)最终运行并清空终结器队列。然后这些对象真正死亡,并被收集到跟踪线程的next 集合中。 (当然,因为他们刚刚从第一次收集中幸存下来,所以他们可能处于更高的世代。)
正如我所说,这过于简单化了;终结器队列如何工作的确切细节比这要复杂一些。但它得到了足够的想法。这里的实际结果是,您不能假设调用 Collect
也会运行终结器,因为它不会。让我再重复一遍:垃圾收集器的跟踪部分不运行终结器,Collect
只运行垃圾收集器的跟踪部分征集机制。
如果您想保证所有终结器都已运行,请在调用 Collect
之后调用恰当命名的 WaitForPendingFinalizers
。这将暂停当前线程,直到终结器线程开始清空队列。如果你想确保那些最终确定的对象回收它们的内存,那么你将不得不 第二次 调用 Collect
。
当然,不言而喻,您只应出于调试和测试目的执行此操作。没有真正、真的充分的理由,永远不要在生产代码中做这种无意义的事情。
关于c# - GC.Collect() 和完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13954829/