Graphics related Memory Leak

Ehsanit

Well-known member
Joined
Feb 23, 2011
Messages
80
Programming Experience
1-3
I'm working on a simple program to project some numbers onto a screen, and it seemed to be working well. However I've since realized that there's a serious memory leak, adding over 4MB to the RAM usage every time the numbers update (which can be once a second or even faster)!

The problem code is as follows:
    Private Sub RefreshNumbers()
        BMP = New Bitmap(Me.Width, Me.Height) ' Transparent Background for painting numbers onto
        Gr = Graphics.FromImage(BMP) ' Unlocks graphics commands including painting onto BMP

        For Corner As Byte = 0 To CByte(DispMode) ' Draws between 1 and 4 numbers onto the blank bitmap
            Dim StringSize As SizeF = Gr.MeasureString(DispStrings(Corner), New Font("Seguo Script", TextSize, System.Drawing.FontStyle.Bold Or System.Drawing.FontStyle.Italic))
            Gr.DrawString(DispStrings(Corner), New Font("Seguo Script", TextSize, System.Drawing.FontStyle.Bold Or System.Drawing.FontStyle.Italic), Brushes.Green, CSng(SectionLeft(Corner) + ((SectionWidth - StringSize.Width) / 2)), CSng(SectionTop(Corner) + ((SectionHeight - StringSize.Height) / 2)))
        Next

        Me.BackgroundImage = BMP ' Displays the bitmap.
        Me.Refresh()
    End Sub


I realize that the problem arises on the first line when I set BMP to a new (transparent) bitmap the size of my screen without removing the previous one. However I cannot work out how to remove the previous one at all, nor why it isn't being removed.
 
Last edited:
You assign a new image to BackgroundImage property, but fail to Dispose the existing one.
The local Graphics instance created in this method you also must Dispose when done with.
Same goes for the Font objects you create, assign them to variables, use them and Dispose when done.
You probably won't see any difference in "numbers" when properly disposing these objects, but in the long run it will be crucial for the automatic memory management and the use of unmanaged resources.
 
Thank you for the heads up on the other objects. I didn't realize that the fonts was doing the the same thing, but it makes a lot of sense. I'll fix that one now.
 
You probably won't see any difference in "numbers" when properly disposing these objects,

What do you mean by this? Will the RAM usage keep climbing, but I should just rely on it releasing memory when it gets too high? As is the program should run at about 14MB, but was climbing into hundreds of megabytes if I left it on timer mode for a minute.

I still can't work out how to access the old image to dispose it once both BMP and Me.BackgroundImage point to the new one.
 
What do you mean by this? Will the RAM usage keep climbing, but I should just rely on it releasing memory when it gets too high?
Yes. In appearance that is what it will do. You can read about .Net memory management from many web resources.
I still can't work out how to access the old image to dispose it once both BMP and Me.BackgroundImage point to the new one.
You can get the old image from BackgroundImage property before assigning a new one to it.
 
I've changed my code to the following. It still counts up, but the garbage collector comes in when it gets to about 200mb. I'm tempted to force it to collect earlier, but the web resources you mention indicate that isn't advisable.

Thank you for your help.

        BMP.Dispose()
        BMP = New Bitmap(Me.Width, Me.Height)
        Gr = Graphics.FromImage(BMP)
        Dim drawFont As Font = New Font("Seguo Script", TextSize, System.Drawing.FontStyle.Bold Or System.Drawing.FontStyle.Italic)
        Dim StringSize As SizeF

        For Corner As Byte = 0 To CByte(DispMode)
            StringSize = Gr.MeasureString(DispStrings(Corner), drawFont)
            Gr.DrawString(DispStrings(Corner), drawFont, Brushes.Green, CSng(SectionLeft(Corner) + ((SectionWidth - StringSize.Width) / 2)), CSng(SectionTop(Corner) + ((SectionHeight - StringSize.Height) / 2)))
        Next

        drawFont.Dispose()

        Me.BackgroundImage.Dispose()
        Me.BackgroundImage = BMP
        Me.Refresh()
 
You forgot this:
me said:
The local Graphics instance created in this method you also must Dispose when done with.
Ehsanit said:
I'm tempted to force it to collect earlier, but the web resources you mention indicate that isn't advisable.
That is correct. Neither forced collects or meddling with the automatic allocations is generally advisable.
 
I added a temporary GC.collect statement at the end of the function and sure enough the RAM usage holds constant, so clearly the disposal system is working. I'll trust the Garbage collector do it's own job in the final version.

Thank you once again for your help.
Oh, and for the little links in your signature. They're interesting reading in their own right.
 

Latest posts

Back
Top