In .NET perspective:
The best explanation of how the garbage collector works is in Jeff Richters CLR via C# book, (Ch. 20). Reading this gives a great grounding for understanding how objects persist.
One of the most common causes of rooting objects accidentally is by hooking up events outisde a class. If you hook up an external event
e.g.
SomeExternalClass.Changed += new EventHandler(HandleIt);
and forget to unhook to it when you dispose, then SomeExternalClass has a ref to your class.
As mentioned above, the SciTech memory profiler is excellent at showing you roots of objects you suspect are leaking.
But there is also a very quick way to check a particular type is just use WnDBG (you can even use this in the VS.NET immediate window while attached):
.loadby sos mscorwks
!dumpheap -stat -type
Now do something that you think will dispose the objects of that type (e.g. close a window). It's handy here to have a debug button somewhere that will run System.GC.Collect() a couple of times.
Then run !dumpheap -stat -type again. If the number didn't go down, or didn't go down as much as you expect, then you have a basis for further investigation.
(I got this tip from a seminar given by Ingo Rammer).