Tuesday, October 25, 2011

Memory Leak in a Microsoft .Net Code

I tested my application to run overnight with a background process using a timer control. I had it run overnight and in the morning, after checking, I found a message on my screen stating "Unhandled Microsoft .Net Framework Exception occurred in HiTBP.exe [616]". Of course the application is not running anymore. I was wondering what went wrong.

Immediately after reading the exception, I fired up my Visual Studio 2010 IDE and opened the project. I inspected every procedure with a timer control on the main form and run it. After several minutes, I figured out what is causing the problem. See the code below:

Private Sub TimeOutTimer_Tick(sender As System.Object, e As System.EventArgs) Handles TimeOutTimer.Tick
Try
Dim frm As New frmTimeClock ' - This line here is the one causing the problem

If Auth.CheckLogOutStatus = True Then
AppInfo.IsShowLoginForm = True
' Executing clocking out procedure without showing the TimeClock Form
frm.ClockOut()
Else
Exit Sub
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
Log.LogInformation(Now & " - Error " & Err.Number & " (" & Err.Description & ") on line number " & Erl() & " in procedure TimeOutTimer_Tick of Main Menu Form")
End Try
End Sub

The problem with the code above is every time the timer ticks every 3 seconds, it consumes around 240K of memory also every 3 seconds and accumulates because a new form is always instantiated. After opening the Task Manager and Processes Tab, here's what I get after execution:


To fix the issue I modified the code above to the following:

Private Sub TimeOutTimer_Tick(sender As System.Object, e As System.EventArgs) Handles TimeOutTimer.Tick
Try
If Auth.CheckLogOutStatus = True Then
AppInfo.IsShowLoginForm = True
' Executing clocking out procedure without showing the TimeClock Form
Dim frm As New frmTimeClock
frm.ClockOut()
Else
Exit Sub
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
Log.LogInformation(Now & " - Error " & Err.Number & " (" & Err.Description & ") on line number " & Erl() & " in procedure TimeOutTimer_Tick of Main Menu Form")
End Try
End Sub


You have noticed that I moved the "Dim frm As New frmTimeClock" code inside the "If" condition which is only then that it is instantiated when the condition is meet or True. The lesson is you only need to instantiate a form when it is needed at that particular condition especially if it is under a Timer Control procedure. This is to avoid memory leak in the software you are developing.

After modifying the code, my application stabilizes around 25,000 k. Not bad for a
huge WinForms application. :-)