5

I'm not quite sure how to go about doing this. It is a large app, and we are having GDI object "leaks" on most of our forms.

Is there a tool to help out? Is there a tutorial on how to use such a tool?

Should I just start deleting code from our forms until I narrow the offender down? (there is ALOT of code).

XenoPuTtSs
  • 1,254
  • 1
  • 11
  • 31
  • 2
    How do you know that you're having GDI object leaks? – Jim Mischel Nov 28 '11 at 23:18
  • @JimMischel Our app will crash if we open and close some of our forms many times (one of our most used forms is opened/closed ~75 times before it crashes the whole app). I forget what the exact error was, but it had to do with a 1,000 handle limit in windows (the 1,000 is a registry setting, it can be changed up to ~32,000). I have been looking at this off and on for a few months now (I can't seem to figure out exactly what we are doing wrong, and therefore I can't figure out how to fix it). – XenoPuTtSs Nov 29 '11 at 02:58
  • @XenoPuTtSs sounds more like you need to use adplus to take a memory dump and use winDbg with SOS to see the root cause. The exact error would obviously be very helpful. – Jeremy Thompson Nov 29 '11 at 03:03
  • 1
    So you're not necessarily leaking GDI objects, but rather handles, which could be GDI objects, user controls, etc. It sounds to me like something in your program is maintaining a reference to the form, or perhaps to some controls on the form, when you close the form. That would prevent the form (or the referenced controls) from being disposed properly. Do you have a persistent collection somewhere that's holding references to forms or controls? – Jim Mischel Nov 29 '11 at 03:42

4 Answers4

18

It is pretty rare to exceed the 10,000 object limit for GDI objects only, the garbage collector will take care of them when you don't call their Dispose() method yourself. A much more likely failure mode is exceeding the object limit for windows. Which is very easy to do in Winforms, Controls.Clear() or Controls.Remove() will get you there in a hurry when you don't explicitly dispose the removed controls. The garbage collector can't clean them up.

You can get a good diagnostic from Taskmgr.exe, Processes tab. View + Select Columns and tick Handles, USER Objects and GDI Objects. Observe these numbers for your process while you use it. A steadily climbing number of one of them is a sure sign you'll get Windows to bomb your program when it refuses to give you any more. The default quota is 10000 for each. USER Objects is the one that indicates you have a problem with Controls.Clear/Remove, GDI Objects is the one that indicates that you are leaking System.Drawing objects. Perfmon.exe is a good tool to see if the garbage collector is running often enough to get non-disposed System.Drawing objects released.

With the common wisdom that calling Dispose() explicitly where required is a good practice. Especially for Image and Bitmap objects, they take very little GC memory but lots of unmanaged memory, pretty easy to bomb a program with OOM when you don't dispose them. Beware the nasty trap in Properties.Resources, you get a new object every single time you use it and it needs to be disposed. Always use the using statement in painting code.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • >>Controls.Clear() or Controls.Remove() will get you there in a hurry when you don't explicitly dispose the removed controls. The garbage collector can't clean them up.<< Oh, really? How comes -- nobody points to it, so gcoll can pick it up, why not? – TheBlastOne Nov 29 '11 at 12:07
  • 3
    The removed controls are kept alive by parenting them to a hidden window called the "parking window". Ready to be re-parented to another window. Very nice feature since it keeps the native window intact. But it that move doesn't happen, or they are not disposed, they'll leak forever. – Hans Passant Nov 29 '11 at 12:36
  • I was using taskmgr.exe and I was watching my GDI objects climb higher and higher. Eventually it reaches a limit (10,000) and the app crashes (btw, the 10,000 is configurable through the registry "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota") Is the term "parking window" official, if not, what is this feature called? – XenoPuTtSs Nov 29 '11 at 13:57
  • Forget about the parking window, it isn't the cause of your problem. The registry hack is useless, it just postpones the inevitable. You'll need to find the leak. Single-step painting code while keeping an eye on the GDI Objects counter. A good profiler is advisable. – Hans Passant Nov 29 '11 at 14:09
  • @HansPassant Do you know of a good profiler? I was just mentioning the registry change because lowering the number helped me to reproduce the error in a timely manner. – XenoPuTtSs Nov 29 '11 at 14:22
  • 2
    >>Very nice feature since it keeps the native window intact. << I don´t see why I could´nt keep references to the controls I want to reparent later. Isn´t the parking window a just-in-case-mechanism that is "useful" exactly in the scenarios where you could easily keep a reference yourself? Is it documented? – TheBlastOne Dec 01 '11 at 10:31
1

Turns out that I just used Task Manager and tried reproducing the problem. Our issue with our app (and the GDI object leak) was that we were using a static object and binding to it. There was/is a bug with .net 3.5 (atleast) where the form when closing will not know how to dispose of everything correctly and certain graphic object will remain in memory.

XenoPuTtSs
  • 1,254
  • 1
  • 11
  • 31
  • 1
    can you provide the source of your statement? is that bug filed? can we track it? thanks – sebagomez Apr 12 '13 at 13:37
  • I filed something with MSDN and it was closed saying it wasn't going to be fixed. But in another one of my questions (http://stackoverflow.com/questions/8343109/possible-bug-with-net-winforms-or-am-i-just-missing-something-gdi-object-leak) i posted the exact code to reproduce the issue. – XenoPuTtSs Apr 12 '13 at 17:21
1

You could use perfmon (windows->start->perfmon) to monitor the GDI Leak. This has the capability to monitor and log the data in a csv file.

Raghu K Nair
  • 3,854
  • 1
  • 28
  • 45
  • ? GDI objects do not seem to be tracked by performance counters: https://technet.microsoft.com/en-us/library/cc958260.aspx – xverges Oct 24 '16 at 11:39
1

Get a copy of Red Gate’s Memory Profiler. http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/

ahazzah
  • 756
  • 1
  • 7
  • 18