I have a fairly large application written in VB.NET which seems to be suffering from a memory leak of one kind or another. Several times per day, I have instances of this application that crash (seemingly at random, but always after being used for almost a day). I've searched and read many forums and even questions asked here on Stack Overflow about this particular problem. What I've determined is that this is related to a memory leak and usually points to either the handles exceeding 10,000 or the objects exceeding the limit.
I've downloaded the memory pro filer and have used it to locate and fix several memory leaks in the program but that hasn't seemed to slow down the daily crash count. My program uses a global error catcher to log these events and store information about them in the database. I've now got about 2 months worth of data but the error message doesn't really help point me in any kind of direction. I've recently added the ability for this global error catcher to log the handles that the application has and so far it has been far below the 10,000 handle threshold. Usually it is under 1,000.
Long story short, my question is this. Is there some way to log the GDI object count so I can determine if that is causing my program to crash? Are there other 'objects' that might be causing the memory leak and crash besides these two and can I log those some how?
I've tried reading as much as I can and I just can't get a good grasp on this so I appreciate any direction you can give me. It seems like these types of problems plague a lot of programs. Hopefully someone can help me and this can help others in the future.
A little more information about my program and environment. It mostly runs on Windows 7 64 bit machines (although some vista and XP machines are present), it is running on .NET 4.0 framework. The project consists of a few hundred forms, classes, and custom controls (built specifically for this project). I'm using .NET memory profiler 4.6 to check for memory leaks. I've run what I consider the most resource intensive operations on my computer for over an hour (opening and subsequently closing a lot of the screens, crunching gigs worth of data, etc...) while watching the resources in the task manager (Handles, Threads, USER Objects, and GDI Objects) but none of them go over 1000.
Here is a copy of one of the logs from a crash event:
Loaded Assembly: GlobalFuncs, Version=1.0.3391.14822, Culture=neutral, PublicKeyToken=null
Loaded Assembly: Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly: MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d
Loaded Assembly: SQL Database, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Loaded Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly: System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly: System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly: System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly: System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly: System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly: System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly: System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly: System.Speech, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Loaded Assembly: System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
OS Name: Microsoft Windows 7 Professional
OS Version: 6.1.7601.65536
OS Platform: x64
Physical Memory: 1.91GB / 3.90GB (Free / Total)
Virtual Memory: 1.66GB / 2.00GB (Free / Total)
Error Output:
System.ComponentModel.Win32Exception (0x80004005): Error creating window handle.
at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)
at System.Windows.Forms.Control.CreateHandle()
at System.Windows.Forms.TextBoxBase.CreateHandle()
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.RichTextBox.get_TextLength()
at System.Windows.Forms.TextBoxBase.AdjustSelectionStartAndEnd(Int32 selStart, Int32 selLength, Int32& start, Int32& end, Int32 textLen)
at System.Windows.Forms.TextBoxBase.GetSelectionStartAndLength(Int32& start, Int32& length)
at System.Windows.Forms.TextBoxBase.AppendText(String text)
at SWOT.My.MyApplication.ShowDebugOutput(Exception ex)
at SWOT.My.MyApplication.app_ThreadException(Object sender, ThreadExceptionEventArgs e)
at System.Windows.Forms.Application.ThreadContext.OnThreadException(Exception t)
at System.Windows.Forms.Control.WndProcException(Exception e)
at System.Windows.Forms.Control.ControlNativeWindow.OnThreadException(Exception e)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext context)
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
The only other though I had was that my global error catcher is crashing when it tries to load because it cannot create any more handles and I'm somehow losing that information. But the times when it isn't crashing and it is able to log the handle count it is quite low (sub 1000). Is the garbage collector freeing up a lot of resources right after the crash before the program can log the high handle count? I'm just a little lost and confused about the data I have.
Based on the fact that the error output states you have quite a lot of memory (over 1GB) and the error message is "Error creating window handle", I suspect that your app is running into a problem with not freeing handles, rather than not freeing memory. The most likely cause of not freeing handles is using P/Invoke calls. You can just search your code for
Declare
andDllImport
to see if you are actually using any P/Invoke functions. If you are, you'll need to do a detailed review of each function you call and if it returns any handles (via aIntPtr
or a SafeHandle-derived classes). If any of those calls creates a Handle - especially a window handle (often abbreviated as hWnd), then you need to verify that your code frees the hWnd.If you are not using any DllImport/P/Invoke code then most likely you are calling one indirectly via managed code such as creating a new
System.Windows.Forms.Form
orSystem.Windows.Forms.Control
-derived class (which also creates a window handle) and not not calling Close or Dispose on it. There are other things that create handles too, but those come to mind.