Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Castle Windsor Typed Factory without release does not leak

I am using a Castle Windsor Typed Factory. In our registration code it is set up so it can create a Transient component:

container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IThingFactory>().AsFactory());
container.Register(Component.For<IThing>().ImplementedBy<TransientObject>().Named("TransientObject").LifeStyle.Transient);

From my understanding of the Castle Windsor Typed Factory documentation I thought that a Transient object must be released by a Typed Factory method, otherwise the Typed Factory would keep a reference to the object. I tried to prove this by writing a test that used the method explained in this StackOverflow article.

But to my surprise it doesn't actually fail, implying that although I have not released the transient object back to the factory, it can still be reclaimed by the GC. I'm concerned that perhaps my test is misleading and there really is a leak.

So my question is: is my test wrong, or is the documentation wrong?

Here's the test:

var factory = container.Resolve<IThingFactory>();
WeakReference reference = null;
new Action(() =>
        {
            var service = factory.GetTransientObject();
            reference = new WeakReference(service, true);
        })();

GC.Collect();
GC.WaitForPendingFinalizers();
Assert.That(reference.Target, Is.Null, "reference should be null");
like image 245
MrBlueSky Avatar asked Oct 28 '16 15:10

MrBlueSky


1 Answers

Windsor tracks Transient instances only if they have some decommission concerns. A typical example of a decommission concern is that a class implements IDisposable interface.

So, if the IThing is Transient and it does not implement IDisposable and it does not have any other decommission concerns then Windsor will NOT track it and garbage collector can/will remove instances of IThing.

BUT (and this is a big but), I suggest you do not ever rely on this behavior. IThing may be changed by a developer and it may become disposable in the future. Or it may get another decommission concern. And suddenly a memory leak occurs. Therefore a simple rule should be followed:

Any time an object is resolved explicitly by calling container.Resolve it has to be released by calling container.Release. Also any time an object is created explicitly by a typed factory, it has to be destroyed explicitly by the typed factory. Does not matter if the object is transient or not, take care of its lifetime. Always. Creator of an object (be it windsor or typed factory) is responsible for destroying of the object.

Basically, @piotrwest was right in his comment. However, this answer aims to explain that it is not only about IDisposable - it is about decommission concerns (IDisposable is simply one of them).

This great article explains more details.

like image 114
Anton Avatar answered Nov 10 '22 22:11

Anton