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 ! { .... } } }
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.
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.
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.
On garbage collection the order of that collection is not defined:
this
is collecteddisposeLock
is collectedOr
disposeLock
is collectedthis
is collectedSo 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 } }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With