I've been tearing my hair out over a resource leak problem in a WinForms program I've developed. Users report errors such as:
System.OutOfMemoryException: Out of memory.
at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
at System.Drawing.BufferedGraphicsContext.CreateBuffer(IntPtr src, Int32 offsetX, Int32 offsetY, Int32 width, Int32 height)
The operation completed successfully
at System.Windows.Forms.Control.FontHandleWrapper..ctor(Font font)
at System.Windows.Forms.TreeView.CustomDraw(Message& m)
Users get this error after intensive use of the program for a few hours.
I think it's all related to my use of the FlowLayoutPanel control, where I dynamically add UserControls, instantiated by code. These UserControls are then removed from the FlowLayoutPanel and Disposed, to be replaced by others, etc. The UserControls are panels with TreeViews on them, + a label and button.
I have created a very simple new WinForms program, with just a main form and a Timer. The timer creates, and disposes an empty UserControl (with just one label, using a bold font) at each Tick. That's all. I've set the timer interval to 1 ms. Setting it slower makes no difference, so there is no timing issue in my test. (the interval is enough to allow the code to run and GCs to take place).
Interestingly, running this simple test under MemoryProfiler, shows that huge amounts of undisposed instances are left behind for the following types:
The first (EventHandlerList) doesn't worry me much, since I read in these forums that this is not necessarily a resource or memory leak (?).
The Font and FontFamily types however (and also WindowsFont in my original program) DO worry me, and may be the key to my problems.
What's a bit strange is that the Profiler snapshots show 10 million Undisposed instances (after running a night at 1ms interval), and the Realtime display reports 15 million.
What I'd like to find out now is to make sure that I'm not on some wrong track with my tests, and that I'm just seeing artifacts.
The sequence (C#) that I execute in my test is:
UserControl uc = new UserControl1();
uc = null;
It seems that creating a UserControl and then Disposing it does not actually dispose all of its resources?
Here are screendumps of the MemProfiler snapshow and realtime windows:
And here is a ZIP of the simple test program I described:
I'd be extremely grateful for any advice on this. Thanks!