I have a WindowsForms app that appears to leak memory, so I used Redgate's ANTS Memory Profiler to look at the objects I suspect and find that they are only held by objects already on the Finalizer Queue. Great, exactly what is a the Finalizer Queue? Can you point me to the best definition? Can you share any anecdotal advice?
Also, all the root GC objects on the Finalizer Queue are instances of System.Windows.Forms.Control+ThreadMethodEntry objects named "caller". I see that it is involved in multi-thread UI interaction, but I do not know much beyond that. Forgive my apparent laziness and admitted ignorance, but these resources are all buried within a vendor's component. I am talking to the vendor about these issues, but I need some direction to get me up to speed on the conversation. Can you point me to the most useful definition of ThreadMethodEntry too? Any anecdotal advice?
Also, should I even be concerned about these objects on the finalizer queue?
Update: This Red Gate article was helpful.
The finalizer queue holds all objects that have a finalizer method defined. Recall that a finalizer is a means to collect unmanaged resources like handles. When the garbage collector collects garbage, it moves any objects with a finalizer into the finalizer queue. At some point later-- depending on memory pressure, GC heuristics, and the phase of the moon-- when the garbage collector decides to collect these objects, it walks down the queue and runs the finalizers.
Having worked with memory leaks in the past, seeing a bunch your vendor's objects in the finalizer queue could be sloppy code, but it does not indicate a memory leak. Typically, good code will expose a Dispose method that will collect both managed and unmanaged resources, and in doing so, remove themselves from the finalizer queue via GC.SuppressFinalize()
. So, if the vendor's objects do implement a Dispose method, and your code doesn't call it, that could lead to a bunch of objects in the finalizer queue.
Have you tried creating a snapshot in ANTS between two points in time and comparing the objects created between them? That may help you identify any managed objects being leaked.
Also, if you want to see if the memory goes away when the finalizers are run, try this just to test with:
System.GC.Collect(); System.GC.WaitForPendingFinalizers(); // this method may block while it runs the finalizers System.GC.Collect();
I do not recommend running this code normally. You might want to run it if you've just done a ton of work and created lots of garbage. For example, in our app, one of our functions can create about 350 MB of garbage that goes to waste after closing an MDI window. Since this is known to leave lots of garbage, we manually force garbage collection.
Also note that there is a low-level property cache in the base Windows.Forms code that will hold on to the last opened modal dialog. This could be a source of a memory leak. One sure way to get rid of this reference is to force another simple dialog to appear, then run the above GC code.