views:

569

answers:

3

In relation to my previous question, I need to check whether a component that will be instantiated by Castle Windsor, can be garbage collected after my code has finished using it. I have tried the suggestion in the answers from the previous question, but it does not seem to work as expected, at least for my code. So I would like to write a unit test that tests whether a specific object instance can be garbage collected after some of my code has run.

Is that possible to do in a reliable way ?

EDIT

I currently have the following test based on Paul Stovell's answer, which succeeds:

     [TestMethod]
    public void ReleaseTest()
    {
        WindsorContainer container = new WindsorContainer();
        container.Kernel.ReleasePolicy = new NoTrackingReleasePolicy();
        container.AddComponentWithLifestyle<ReleaseTester>(LifestyleType.Transient);
        Assert.AreEqual(0, ReleaseTester.refCount);
        var weakRef = new WeakReference(container.Resolve<ReleaseTester>());
        Assert.AreEqual(1, ReleaseTester.refCount);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Assert.AreEqual(0, ReleaseTester.refCount, "Component not released");
    }

    private class ReleaseTester
    {
        public static int refCount = 0;

        public ReleaseTester()
        {
            refCount++;
        }

        ~ReleaseTester()
        {
            refCount--;
        }
    }

Am I right assuming that, based on the test above, I can conclude that Windsor will not leak memory when using the NoTrackingReleasePolicy ?

+2  A: 

Perhaps you could hold a WeakReference to it and then check to see that it no longer alive (i.e., !IsAlive) after the tests have completed.

dpp
That would only test if it HAS been garbage collected.
Ray
@Ray: true, but the process would be to force a GC, wait for finalizers and then check IsAlive.
dpp
+20  A: 

This is what I normally do:

[Test]
public void MyTest() 
{
    var reference = TestInternal();

    GC.Collect();
    GC.WaitForPendingFinalizers();
    Assert.IsNull(reference.Target);
}

private WeakReference TestInternal()
{
   var service = new Service();
   // Do things with service that might cause a memory leak...
   return new WeakReference(service, true);
   // Service should have gone out of scope about now, 
   // so the garbage collector can clean it up
}

NB: There are very, very few times where you should call GC.Collect() in a production application. But testing for leaks is one example of where it's appropriate.

Paul Stovell
Thanks. I understand that I generally should not call GC.Collect, I needed this to test parts of my code which I suspected was leaking memory.
driis
Excellent bit of code sir +1
annakata
+1. nice one paul!
Mitch Wheat
+1  A: 
AaronBa