views:

98

answers:

3

Q. Is there a way to find out if an object has any "strong references" to it?


Raymond Chen hinted that a solution might be possible:

You want to know whether the reference count is zero or nonzero. For that, use WeakReference.

Notes

  • i have a "weak reference" to the object (using a WeakReference). If i had a strong reference the answer would immediatly be: "Yes. You have a strong reference to the object."
  • the garbage collector exposes no answers
  • the IsAlive property can only tell you if an object has been collected, or not. Not if there are strong references to it, or not. (An object with no references can be uncollected - the GC just hasn't gotten around to it yet)
  • objects in .NET are not reference counted
  • not all objects have to implmenet the IDisposable interface
  • not all objects are mine

Code Sample

This code sample demonstrates the problems with relying on forcing a garbage collection and the WeakReference's IsAlive property to determine if an object has any outstanding references to it.

WeakReference m_wr = null;

...

for (int i = 0; i < 1000000; i++)
{
   Pig p = new Pig();
   m_wr = new WeakReference(p);
}

...

GC.Collect();
if (m_wr.IsAlive)
   Environment.FailFast("All objects should have been collected by now");
+5  A: 

Nope, not without using the debugger API.

As you say, objects aren't reference counted... so the only way of finding out would be to crawl the heap, which normally just happens as part of garbage collection.

Note that even after there are no "normal" strong references, the object could be resurrected as part of finalization anyway - effectively the finalizer queue has a reference to it, if it has a finalizer. Maybe you wouldn't want to include the object as "reference-less" in that situation anyway.

Jon Skeet
"No" was the answer i assumed. We'll see if anyone disagrees. But with you 205k of rep, i think you're going to be the authority on this.
Ian Boyd
+2  A: 

You should read Raymond Chen's post about Reference counts from yesterday. After that - you should decide if that's something you really need to do and why. Then come back and tell us why.

Hmm, it seems you've read the post - absorbed minor details and missed the point.


i want to know if it's safe to call Dispose on a database connection.

Read the docs. Dispose calls Close. Close is safe to call as much as you like.

An application can call Close more than one time. No exception is generated.

David B
All implementations of `IDisposable.Dispose` should behave nicely if called more than once. Furthermore, finalizers should also behave the same way, because already-finalized objects can be resurrected and re-finalized.
Tim Robinson
i added a comment to original question stating why. You will find my name in the comments of that blog post, asking the same question - that's when i decided to ask here. Also, calling `Dispose` or `Close` twice on a database connection is not the worst that can happen.
Ian Boyd
Also, **important point**, i wasn't asking about reference counts.
Ian Boyd
+2  A: 

First call GC.Collect() and then check WeakReference.IsAlive. If it is true (i.e., it hasn't been collected after calling GC.Collect) then there is a strong reference somewhere.

Mark Cidade
+1 for correctness. However, if you call GC.Collect to check object reference counts, you will push objects into later generations - making them live longer if you ever stop manually invoking the GC. As such - this is a bad practice.
David B
Not technically correct. That forcing a generation-zero collection does not guarantee that the object in question will be collected: It may have been promoted into a higher generation
Ian Boyd
It'll only be promoted to a higher generation if there are still outstanding references. If the GC determines there are no references, it'll be left alone or collected.
Tim Robinson
@Tim Robinson It's not strictly true. There is a heuristic involved in promoting objects to higher generations. It's not something you can count on now. And it's certainly not documented to not change tomorrow. Also, objects *never* being collected is a valid scenario (i.e. the `null` garbage collector is a valid garbage collector). Nothing says that the garbage collector has to do anything when you call `Collect` - that's an internal implementation detail.
Ian Boyd
@Ian: MSDN says, that GC.Collect "forces an immediate garbage collection of all generations." http://msdn.microsoft.com/en-us/library/xe0c2357.aspx
Mark Cidade
@Mark Cidade The GC is allowed to do nothing. Also because it's threaded, it's a race condition.
Ian Boyd
Where does it say that the .NET GC may do nothing when calling GC.Collect()? Chen's null GC argument is only theoretical. And I don't see how it's a race condition since GC.Collect() doesn't return until it's completed the collection.
Mark Cidade
@Mark Cidade It doesn't say that the GC may do nothing when calling `GC.Collect()`; nor does say what the GC will do. It says "Forces an immediate garbage collection of all generations."). An optimization that is allowed to exist where it does nothing, "Okay, i've performed the collection operations - and i collected nothing since there's no memory pressure."
Ian Boyd