Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Readonly fields becomes null when disposing from finalizer

Tags:

I've the following class. Now sometimes the lock statement is throwing an ArgumentNullException, and in that case I can then see in the debugger that disposelock object is really null.

As I can see that disposing is false, I know that the method is triggered from Finalizer.

But how can this happen ? It is defined as readonly and gets its value when the object is created.

PS: I know that this isn't a good pattern, but its part of a given code, and I just can't explain why this becomes 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 !        {            ....        }    } }            
like image 580
Boas Enkler Avatar asked Nov 10 '15 07:11

Boas Enkler


People also ask

What happens if Dispose is not called?

Implement a finalizer to free resources when Dispose is not called. By default, the garbage collector automatically calls an object's finalizer before reclaiming its memory. However, if the Dispose method has been called, it is typically unnecessary for the garbage collector to call the disposed object's finalizer.

How Dispose works in c#?

The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.

When to implement Dispose c#?

We should use an IDisposable design pattern (or Dispose Pattern) when we need to dispose of unmanaged objects. For implementing the IDisposable design pattern, the class which deals with unmanaged objects directly or indirectly should implement the IDisposable interface.


2 Answers

On garbage collection the order of that collection is not defined:

  1. First this is collected
  2. Next disposeLock is collected

Or

  1. First disposeLock is collected
  2. Next this is collected

So do not use any reference fields (structs like int, bool etc. are safe) on 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   } } 
like image 108
Dmitry Bychenko Avatar answered Sep 22 '22 03:09

Dmitry Bychenko


All existing answers except the reflection answer are false. The GC does not set references to null when it collects objects. Object access does not spuriously fail due to the GC. The order of finalization is undefined but all object references that exist continue to exist and are valid.

My guess for what happened: The constructor was aborted before the field was initialized. That left the field null. The finalizer then later found it like that.

A constructor can be aborted by throwing an exception, or by calling Thread.Abort which is evil.

On garbage collection the order of that collection is not defined

The order of collection is not observable (except through weak references...). The order of finalization is observable, but not with the lock statement because objects do not loose the ability to synchronize when finalized.

like image 25
usr Avatar answered Sep 18 '22 03:09

usr