[.net] when to dispose of .net IDisposable member variables

Started by
3 comments, last by dmatter 14 years, 11 months ago
Hi, I'm trying to get to grips with Garbage Collection in .Net, and have a couple questions: Say I have an object that has member variables that implement the IDisposable interface - for example the member variables might be a TextureBrush. The Brush type implements IDisposable and is therefore unmanaged, meaning I need to dispose of it manually. Is this statement correct? So, I go ahead and make my class IDisposable, giving the following:

    Private disposedValue As Boolean = False        ' To detect redundant calls

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)

        If Not Me.disposedValue Then

            If disposing Then

                ' free other state (managed objects).
                If Not IsNothing(m_textureBrush) Then
                    m_textureBrush.Dispose()
                End If

            End If

            ' free your own state (unmanaged objects). Set large fields to null.
            m_textureBrush = Nothing

        End If

        Me.disposedValue = True

    End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub



When I know that an object is no longer needed, I remove all references to it and call its dispose method. What happens when my application shuts down? Do I still have to call dispose on these objects or does .Net clean it all up automatically? I ask, because when debugging, my Dispose methods are not called automatically when I close the application.
Advertisement
If a class implements IDisposable this does not mean it is unmanaged. It is still a managed type, and the garbage collector will still clean it up if it is out of scope when a collection occurs. Instead what it means is that the class has a reference to unmanaged resources, and if you call Dispose then these unmanaged resources will be cleaned up.

The reason why you want these kinds of classes to have a Dispose method is because the unmanaged memory isn't visible to the garbage collector. For instance, take an instance of the System.Drawing.Image class. Say you create one from a 1024x1024 24-bit .bmp file. When you create it, the GC only sees the managed footprint of the instance which will probably be a few hundred bytes or so. However it doesn't see the huge 3 megabytes of bitmap data that's sitting in native memory.

Now the reason this is a problem is because of how the GC works. The GC typically begins a collection after a certain amount of managed memory is allocated. Until you've reached that threshold, no garbage will be collected. So let's say you have an app where every time you hit a button, you load up a new Image from a bitmap file and this Image replaces your previous Image. Each time you load up a new one, you're loading a few megabytes of data into native memory...however you're only allocating a few hundred bytes of managed memory. This means that the user can keep clicking and your app will start to have a very large footprint in native memory, since no collections are occuring.

Dispose helps solve this problem. Since Image implements IDisposable, you could call Dispose on it every time you replace it. This ensures that the native memory gets cleaned up, even if no collection occurs.

To answer your last question, you don't need to call Dispose when you're shutting down. The garbage collector will handle cleaning up everything when this happens. On a similar note the GC will clean up all of your out-of-scope references if you call GC.Collect...this and be a simpler alternative to calling Dispose on a lot of objects if you're getting rid of a whole bunch of references at once. However it's not something you want to do *all the time*, since it will cause a full non-generational collection which won't be quick.
Quote:Original post by Paulus_newbieus
When I know that an object is no longer needed, I remove all references to it and call its dispose method.
What happens when my application shuts down? Do I still have to call dispose on these objects or does .Net clean it all up automatically?
If you have already called dispose then you do not need to call it again, at shutdown the garbage collector will just reclaim any managed resources as usual, you should make sure to explicitly call the dispose method, or use RAII and wrap things in a Using statement, as otherwise there is no autmomated calling of this method.

You can, however, write a finalizer method that is automatically called when the garbage collector decides to reclaim an object, it is common for the finalizer to simply make a call to dispose, this covers the case where you forgot to call dispose yourself. It still isn't good to rely on the finalizer since since you don't usually want to leave unmanaged resource lying around and taking up space for longer than is necessary, you quite often need deterministic destruction of unmanaged resources.
Ok thank you dmatter, I think I got it.

How about re-assigning local IDisposable variables? Take the Bitmap as an example - if I have a 100*100 bitmap in a local variable, but then need a new smaller bitmap and create a 50*50 image and just assign it to the same local variable, do I have to make sure I disposed it first so that the larger image is cleared from native memory?

E.g.

       If Not IsNothing(m_bmpImage) Then            m_bmpImage.Dispose()            m_bmpImage = Nothing        End If        m_bmpImage = New Bitmap(m_intWidth, m_intHeight, Imaging.PixelFormat.Format32bppPArgb)


If you have a finalize method to clear up the unmanaged memory then it will - at some point - get disposed of, it'll be when the garbage collector calls the finalize method. Calling dispose yourself just before you reassign the variable will clean it up there and then.

This topic is closed to new replies.

Advertisement