从终结器处理时,只读字段变为空

Boa*_*ler 22 .net c# garbage-collection

我有以下课程.现在有时锁定语句会抛出一个ArgumentNullException,在这种情况下,我可以在调试器中看到该disposelock对象实际上是null.

我可以看到处理是错误的,我知道该方法是从Finalizer触发的.

但这怎么可能发生呢?它被定义为只读,并在创建对象时获取其值.

PS:我知道这不是一个好的模式,但它是给定代码的一部分,而我无法解释为什么这个变为null

public abstract class DisposableMarshalByRefObject : MarshalByRefObject, IDisposable
{
    private readonly object disposeLock = new object();


   /// </summary>
   ~DisposableMarshalByRefObject()
   {
       Dispose(false);
   }

   /// <summary>
   /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
   /// </summary>
   public void Dispose()
   {
       Dispose(true);
       GC.SuppressFinalize(this);
   }

   protected void Dispose(bool disposing) //disposing = false,=> finalizer
   {
       lock (disposeLock) //ArgumentNull Exception !
       {
           ....
       }
   }
}           
Run Code Online (Sandbox Code Playgroud)

Dmi*_*nko 7

垃圾收集时,未定义该集合的顺序:

  1. this收集
  2. 接下来disposeLock收集

要么

  1. disposeLock收集
  2. 接下来this收集

因此,不要使用任何引用字段(结构类似int,bool等等是安全的)Dispose(false);

protected virtual void Dispose(bool disposing) {
  if (disposing) {
    // Explicit disposing: it's safe to use disposeLock 
    lock (disposeLock) {
      ...
    }
  } 
  else {
    // Garbage collection: there's no guarantee that disposeLock has not been collected
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 收集对象时,其引用不会设置为null.这并不能解释为什么该字段为空.由于锁只是一个"对象",因此GC根本不会处理它,直到它真正无法访问. (3认同)
  • 你确定吗?具有尚未触发的终结器的AFAIK恢复对象及其引用的所有对象.没有定义的是调用终结器的顺序.虽然未指定收集顺序,但是在终结器运行之后才能收集任何对象,并且您只能通过弱引用来观察此未定义的顺序,这些引用未在示例中显示. (2认同)
  • 具有终结器的AFAIK对象暂时阻止从中可以访问的所有对象的集合(但不是最终化).如果它永久地复活,那些引用的物体将自己永久复活. (2认同)

usr*_*usr 5

除反思答案外,所有现有答案均为假.GC在收集对象时不会将引用设置为null.由于GC,对象访问不会发生虚假失败.最终确定的顺序是未定义的,但存在的所有对象引用仍然存在且有效.

我对发生的事情的猜测:构造函数在字段初始化之前被中止.那离开了这个领域null.终结者后来发现了那样.

可以通过抛出异常或通过调用Thread.Abort哪个是邪恶来中止构造函数.

在垃圾收集时,未定义该集合的顺序

收集的顺序是不可观察的(除非通过弱引用......).最终确定的顺序是可观察的,但不能与lock语句一起使用,因为对象在最终确定时不会失去同步的能力.

  • (dis)证明了这个解释,在构造函数中插入一个日志调用(表明该对象已经完全构造),并且如果你得到一个抛出空引用异常的finializer,检查你的日志以查看它的构造函数是否为finshed , 或不. (2认同)