为什么在终结器中序列化对象不是一个好主意?

Why is it not a good idea to serialize an object in its finalizer?

在 Headfirst C# 一书中,我的观点是 "it's not a good idea to serialize an object in its finalizer, since serialization requires the whole object tree to be in the heap, but you may end up with missing vital part of your program because some objects might’ve been collected before the finalizer ran."

我的问题是,由于我的对象获得了对其他对象的引用(这意味着至少有一个对其他对象的引用),如何在我的终结器运行之前对它们进行垃圾回收?

因为垃圾收集器没有定义任何 运行 终结器的顺序,并且不关心您的对象是否乱序终结。

当你的终结器运行时,GC 已经决定它和它引用的每个对象都是不可访问的,因此所有这些子对象也将被收集。这些对象中的每一个都被添加到终结器队列中,但是不能保证GC 将以任何表面上合理的顺序处理它们。

这是您可以在终结器中执行的操作的限制之一:您必须假设所有子对象都可能已经被销毁。 Object.Finalize 的文档明确指出了这一点:

The finalizers of two objects are not guaranteed to run in any specific order, even if one object refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object B might have already been finalized when the finalizer of Object A starts.

终结器的问题在于它们提供的保证很少:

  • 他们不能保证永远 运行
  • 你无法预测他们什么时候会运行
  • 当他们这样做时 运行,他们引用的某些对象可能已经完成,因此您的对象可能不处于有效状态

Eric Lippert 有两篇关于此的精彩博文:

无论如何,您将要编写的 类 中的 99% 应该根本没有终结器。在极少数情况下,它们实际上是必要的。如果您需要在使用完某个对象后执行清理,请改用 IDisposable,至少您可以确定性地控制它。