views:

93

answers:

3

I am looking for a managed/unmanaged API that will allow me to find which objects reference another object and are potentially keeping it from being garbage collected.

Such an API might look like this:

var foo = new Foo();
var bar = new Bar();
bar.Foo = foo;

var references = GC.GetReferencesTo(foo);
// references is an array that contains bar

I know profilers can be used for this but I'd like to make it part of a unit test. Is there a managed or unmanaged API that I could use?

+2  A: 

The unmanaged dll SOS (Son Of Strike) provides a means to achieve this, though I do not believe it has significant scripting support, nor does it provide a simple means to achieve this via a single command. You would have to introspect the variable's address, check all gcroots for the variable (which would include the stack obviously) and deal with the remainder.

I would suggest that, if you wish to prove that an object is not referenced, a simpler technique would be to (temporarily) make it finalizeable, ensure it is no longer referenced on the stack of your unit test and then force several garbage collections via GC.Collect() then use GC.WaitForPendingFinalizers().

Your finalize method can set a static boolean flag and then your unit test can assert this is true.

I would question the utility of this without further explanation but this is likely to be the simplest method of proving no dangling references exist in a unit test.

ShuggyCoUk
I currently use a WeakReference to the object followed by a GC.Collect/WFPF then assert the reference is null to tell me if it's been cleared up. I do this as part of a unit test to ensure my API doesn't cause leaks. But as part of the 'assert' output I'd like to print out which objects are keeping it alive, to save me jumping into the profiler.
Paul Stovell
I seriously doubt that this is possible in an automatic fashion without a vast amount of work to expose the SOS functionality yourself unless someone within MS has done this already. I would suggest that the best thing is to look into writing something based on SOS that automates the entire search into one command so you can trigger it from a failing test in the debugger. Note that SOS is not a standalone tool, it is totally dependant on a compatible debugger being attached...
ShuggyCoUk
If you really want to try to hack it in here's a staring point: http://blogs.microsoft.co.il/blogs/sasha/archive/2009/08/17/gc-helper-for-obtaining-live-instances-of-a-type-or-how-i-implemented-gc-getaliveinstancesof-lt-t-gt.aspx
ShuggyCoUk
also ook at what some people have one in wrapping SOS: http://old.thinktecture.com/SOSAssist/Screenshots.htm
ShuggyCoUk
A: 

Also remember .NET uses traced garbage collection so objects referenced by other objects - e.g. a graph of objects - will still be cleaned up by the GC if your app isn't referencing any of them any longer; it's a lot smarter than the classic reference counting garbage collection algorithms pre-.NET. This means that even when you find a way to pinpoint all references to an object, some of them may not matter and may not need to be taken care of.

This doesn't answer directly how to find all references to an object, but does make readers aware of the the situation that, when you do find all references through a tool or utility, some kinds of things don't need to be fixed any longer in .NET - e.g. classic circular references, and therefore you might have to look for some ingenious ways of knowing what to ignore when trying to fix memory leaks.

This explanation only applies to the managed code scenario.

John K
+2  A: 

.NET Profiler uses the profiling API to trace the graph of objects. You might be particularly interested in callback methods ObjectReferences and RootReferences, and maybe also ObjectAllocated. The first two methods will be called to cover the entire live object graph after every garbage colection, so intercepting them alone is sufficient to rebuild that graph, and then analyze it in any way you want.

This article explains how to put all the pieces together.

Pavel Minaev