I'm using C# but probably the same in VB.NET. I C++ I would just set a break-point on an objects destructor to know when/if it was deleted/free'd. I understand that in winforms the base class calls SupressFinalize so that form destructors are never called, so I guess I can't do it that way. Is there another method to know if an object has been garbage collected? It seems like a catch-22 because if there was you would probably need a reference to check, but by holding that reference the garbage collected will not crush it.

I've read this What strategies and tools are useful for finding memory leaks in .NET?, and I understand there are tools and/or frameworks out there to handle this "big picture" and I'm sure in a few weeks I'll be trying out several of these methods. For now I just have a really strong feeling I might have a leak related to forms not being deleted, so just want to check this one thing (and I want to know just for the sake of knowing).

I know I can watch Dispose, but I'm pretty sure Dispose can be called but still end up with the form object still being around. To test that theory I created a known-issue where I registered for a callback event in my form, then closed the form without unregistering it. Sure enough, Dispose was called (and "disposing" was true), but later when the event was fired, it still hit my break-point inside the form that was supposedly disposed already.

2 Answers
2

As for your original question, you can use a WeakReference to monitor an object's existence without affecting its lifetime.

Your underlying question suggests that you have a misunderstanding of what garbage collection is, and how it works. The point of garbage collection is that you should never care if an object has been collected or not. Instead, you should focus on the references to the object, and if they have been reassigned or made inaccessible from rooted references. Don't worry about the instance, worry about the references to it.

WeakReference.IsAlive will do what I need, thank you. I do understand GC and know that there are tools out there that will show me each reference to an object, and that is what I need to focus on in the long term. For now I was just looking for a way to know if 1 specific object has been collected, this will do that.
–
eselkMay 10 '12 at 15:55

The entire concept of a managed language is that you don't need to care when an object is actually garbage collected. Lots and lots of time and effort go into the GC to make sure that it doesn't collect objects that it shouldn't, that it doesn't leave objects that it should collect (when it decides to do a pass over the generation that it's in) and that all of this is done reasonably efficiently. This means that if an object consumes a large amount of managed resources and also implements IDisposable (say, a DataTable or DataSet) is disposed it is still consuming a lat of memory, and disposing of it doesn't make it get garbage collected any quicker (although you should still dispose of it to ensure any managed resources go away).

The GC is built to work best when you leave it alone and let it do it's job rather than interfering with it by trying to, for example, manually cause collections to take place. This is occasionally useful for debugging purposes or learning about your program/the language, but it virtually never belongs in a production application.

Disposing has nothing to do with garbage collection or collecting an object. Disposing is the mechanism in place for dealing with a managed object that is holding onto an unmangaed resource (or another object that is holding onto an unmangaed resource). Disposing of the object is telling it to clear up that unmanaged resource, but it has nothing to do with the garbage collector freeing the managed resources of that object. The destructor is there so that you don't free the managed resources before freeing the unmanaged resources, but it's perfectly acceptable (and in fact should always happen) that the unmanaged resources are cleaned up (via dispose) before the managed resource is freed.

Now, it is still possible, given all of this, for a program to have a memory leak, but there are a few questions you really need to be asking yourself first. How large is the leak? Is it a one off, continuous over time, every time we do function X, etc? What would it take for the program to consume so much memory as to be disruptive (either run out of memory, cause other programs to run out of memory, etc) and is that likely to occur with common or legitimate uses of the program? Usually you don't need to start asking these types of questions until you start getting out of memory exceptions, or notice that you start running out of physical memory for a program that oughtn't to. If you notice these problems then you can start looking around for objects that implement IDisposable that aren't being disposed, to see if you're holding onto references to very large objects (or collections of objects) that you no longer need, etc.

This is for debug/learning purposes only, not production code. It is part of a production project but this code will not be left in. Just used as one of many tools for me to check for a very specific type of memory leak I want to be sure to avoid -- because it would be an "every time we do function X" and could grow if I happen to pin an object by mistake.
–
eselkMay 10 '12 at 15:58