Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IDisposable implementation - What should go in 'if (disposing)'

I have been fixing some memory leak issues in a winforms application and noticed some disposable objects that are not Disposed explicitly (developer hasn't called Dispose method). Implementation of Finalize method also doesn't help because it doesn't go in if (disposing) clause. All the static event unregistering and collection clearing have been put in if (disposing) clause. The best practice is calling the Dispose if the object is disposable, but unfortunately this happens sometimes

If there are unmanaged objects, static event handlers and some managed collections that needs to clear when disposing. What's the way to decide what should go in and what should go out of if (disposing) clause.

Dispose method.

// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
    if (!disposed)
    {
        if (disposing)
        {
            // Free other state (managed objects).
        }

         // Free your own state (unmanaged objects).
         // Set large fields to null.
         disposed = true;
     }
 }

It says managed objects should in if (disposing) which executes normally only when explicitly call Dispose method by the developer. If the Finalize method has been implemented and developer forgets to call the Dispose method the execution that comes here through the Finalizer does not go in if (disposing) section.

Below are my questions.

  1. If I have static event handlers that causes memory leaks where should I un-register them? In or out of if (disposing) clause?

  2. If I have some collections that causes memory leaks where should I clear them? In or out of if (disposing) clause?

  3. If I am using third party disposable objects (eg: devExpress winform controls) that I am not sure whether they are managed or unmanaged objects. Let's say I want to dispose them when disposing a form. How can I know what are managed and what are non-managed objects? Being disposable doesn't say that? In such cases how to decide what should go in and what should go out of if (disposing) clause?

  4. If I am not sure something managed or unmanaged what can be the bad consequences of disposing/clearing/unregistering-events out of the if (disposing) clause? Let's say it checks for null before disposing?

Edit

What I mean as event un-registering is something like below. Publisher is a long lived instance and below line is in the subscriber's constructor. In this case subscriber need to unregister the event and dispose before the publisher.

publisher.DoSomeEvent += subscriber.DoSomething;
like image 439
CharithJ Avatar asked Oct 04 '11 02:10

CharithJ


People also ask

What is IDisposable interface in C implement the Dispose method?

The Dispose method is automatically called when a using statement is used. All the objects that can implement the IDisposable interface can implement the using statement. You can use the ildasm.exe tool to check how the Dispose method is called internally when you use a using statement.

What should be in Dispose method?

The Dispose() method 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.

Will the Dispose () of IDisposable be called when GC runs in case the instance is not created within using block?

Answer: None. Calling Dispose can release unmanaged resources, it CANNOT reclaim managed memory, only the GC can do that.


1 Answers

Broadly, managed resources are disposed inside if (disposing) and unmanaged resources outside of it. The dispose pattern works as such:

  1. if (disposed) {

    If this object is already disposed, don't dispose of it a second time.

  2. if (disposing) {

    If disposal was requested programatically (true), dispose of managed resources (IDisposable objects) owned by this object.

    If disposal was caused by the garbage collector (false), do not dispose of managed resources because the garbage collector may have already disposed of the owned managed resources, and will definitelty dispose of them before the application terminates.

  3. }

    Dispose of unmanaged resources and release all references to them. Step 1 ensures this only happens once.

  4. disposed = true

    Flag this object as disposed to prevent repeated disposal. Repeated disposal may cause a NullReferenceException at step 2 or 3.

Question 1
Don't dispose of them in the Dispose method at all. What would happen if you disposed of multiple instances of the class? You'd dispose the static members each time, despite them already being disposed. The solution I found was to handle the AppDomain.DomainUnloaded event and perform static disposal there.

Question 2
It all depends if the items of the collection are managed or unmanaged. It's probably worth creating managed wrappers that implement IDisposable for any unmanaged classes you are using, ensuring all objects are managed.

Question 3
IDisposable is a managed interface. If a class implements IDisposable, it's a managed class. Dispose of managed objects inside if (disposing). If it doesn't implement IDisposable, it is either managed and does not require disposing, or is unmanaged and should be disposed outside of if (disposing).

Question 4
If the application terminates unexpectedly, or doesn't use manual disposal, the garbage collector disposes of all objects in random order. The child object may be disposed before it's parent is disposed, causing the child to be disposed a second time by the parent. Most managed objects can safely be disposed multiple times, but only if they've been built correctly. You risk (though, unlikely) causing the gargabe collection to fail if an object is disposed multiple times.

like image 74
Hand-E-Food Avatar answered Sep 20 '22 23:09

Hand-E-Food