Reputation: 3111
I want to test for object references held improperly and wrote a test that always failed. I simplified the test to the following behaviour:
[Test]
public void ScopesAreNotLeaking()
{
WeakReference weakRef;
Stub scope = null;
using (scope = new Stub())
{
weakRef = new WeakReference(scope);
}
scope = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.That(weakRef.Target, Is.Null);
}
This test however, which does the same without using, passes:
[Test]
public void ScopesAreNotLeaking()
{
WeakReference weakRef;
Stub scope = new Stub();
weakRef = new WeakReference(scope);
scope = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.That(weakRef.Target, Is.Null);
}
The used stub class is simple enough:
class Stub : IDisposable
{
public void Dispose() {}
}
Can someone please explain me that behaviour or - even better - has an idea how to make sure that the object gets garbage collected?
PS: Bear with me if a similar question was asked before. I only examined those questions that have using in the title.
Upvotes: 6
Views: 841
Reputation: 22683
I suspect there may be a local introduced by the using statement. Use ildasm to see if all the references in the function to the object are truly cleared before the call to GC.Collect
. Also try to put the using bit in a separate function that returns the weak reference.
Upvotes: 2
Reputation: 29468
The mark & sweep GC, like it is used in .NET, is not deterministic.
Even if called by GC.Collect()
there is no guarantee that is really runs.
Additionally, the using-clause does not have anything to do with garbage collection. If just calls Dispose() on its target object.
Upvotes: 1
Reputation: 8320
using is not designed to force garbage collection but to ensure dispose is called. Dispose allows you to release non-garbage collected resources like file handles. Garbage collection happens when c# is good and ready.
Upvotes: 5
Reputation: 5415
Your two test cases are not identical. At the end of a using
statement, the resource's Dispose
method is called, it is not set to null. Calling Dispose does not necessarily call the destructor.
Upvotes: 1