Try fast search NHibernate

08 October 2010

Castle Windsor InstantiateAndForgetIt Lifestyle

Directly to the point.

The case

public interface IMySingleton : IDisposable
{
}

public class MySingleton: IMySingleton
{
    public void Dispose()
    {
    }
}

public interface IMyTransient
{
}

public class MyTransient : IMyTransient
{
    private readonly IMySingleton singleton;

    public MyTransient(IMySingleton singleton)
    {
        this.singleton = singleton;
    }
}
As you can see it is pretty common: I have a class MyTransient with a dependency from a singleton. The singleton is disposable.
The transient is from the point of view of its usage, that mean that its lifecycle is managed by an “external context” and, as is, it does not need a special “destructor”. The “external context” may hold the instance somewhere or may use it only in the context of a method and can quite leave the destruction to the garbage collector. If/when MyTransient implements IDisposable the “external context” should dispose the instance. You can see this behavior in various places for example in the DefaultControllerFactory of Asp.NET MVC or in the IInstanceProvider of WCF (both has a ReleaseInstance cheking for IDisposable); personally I have this situation in other places.
If I do something like this
var myInstance = new MyTransient(container.Resolve<IMySingleton>());
The garbage collector will have zero problems to destroy myInstance and I’ll have zero memory leaks… that is clear, no ?

The test using Windsor with Transient Lifestyle

public class TransientLeak
{
    private WindsorContainer GetContainerConfiguredWindsorContainer()
    {
        var container = new WindsorContainer();
        container.Register(Component.For<IMySingleton>().ImplementedBy<MySingleton>());
        container.Register(Component.For<IMyTransient>().ImplementedBy<MyTransient>().LifeStyle.Transient);
        return container;
    }

    [Test]
    public void WhenTransientRequiredThenReturnDifferentInstances()
    {
        using (WindsorContainer container = GetContainerConfiguredWindsorContainer())
        {
            var t0 = container.Resolve<IMyTransient>();
            var t1 = container.Resolve<IMyTransient>();

            t0.Should().Not.Be.SameInstanceAs(t1);
        }
    }

    [Test]
    public void WhenTransientRequiredThenContainerShouldntHaveInstancesOfMyTransient()
    {
        using (WindsorContainer container = GetContainerConfiguredWindsorContainer())
        {
            var t0 = container.Resolve<IMyTransient>();
            var t1 = container.Resolve<IMyTransient>();

            container.Kernel.ReleasePolicy.Satisfy(rp=> !rp.HasTrack(t0));
            container.Kernel.ReleasePolicy.Satisfy(rp => !rp.HasTrack(t1));
        }
    }     
}
Well… the first test pass, that means that each time I asking for a IMyTransient I’ll have a new instance of the concrete implementation injected with the same instance of IMySingleton (as expected).

Now take care : The second test fails. That means that the container is holding two instances of MyTransient class; let me show you where:
TransientLeak
Perhaps there is a good explication for this behavior but I must admit that I can’t understand why all instances of MyTransient should have its lifecycle stuck to the lifecycle of MySingleton only because MySingleton is disposable… bah?!? by the way that is not a matter because Castle.Windsor give us the ability to define the behavior we need.

The solution

First of all I need my custom lifestyle manager:
[Serializable]
public class InstantiateAndForgetIt : ILifestyleManager
{
    private IComponentActivator componentActivator;

    public void Init(IComponentActivator componentActivator, IKernel kernel, ComponentModel model)
    {
        this.componentActivator = componentActivator;
    }

    public object Resolve(CreationContext context)
    {
        return componentActivator.Create(context);
    }

    public bool Release(object instance)
    {
        return true;
    }

    public void Dispose()
    {
     
    }
}

Pretty simple but not enough. Then I need an implementation of IReleasePolicy and I can simply inherit from the default and override a method:
[Serializable]
public class LifecycledComponentsReleasePolicy : Castle.MicroKernel.Releasers.LifecycledComponentsReleasePolicy
{
    private readonly Type instantiateAndForgetItType = typeof (InstantiateAndForgetIt);

    public override void Track(object instance, Burden burden)
    {
        if (instantiateAndForgetItType.Equals(burden.Model.CustomLifestyle))
        {
            return;
        }
        base.Track(instance,burden);
    }
}

The last step is the modification of the container’s configuration:
private WindsorContainer GetContainerConfiguredWindsorContainer()
{
    var container = new WindsorContainer();
    container.Kernel.ReleasePolicy = new LifecycledComponentsReleasePolicy();
    container.Register(Component.For<IMySingleton>().ImplementedBy<MySingleton>());
    container.Register(Component.For<IMyTransient>().ImplementedBy<MyTransient>().LifeStyle.Custom<InstantiateAndForgetIt>());
    return container;
}


Work done!! and bye bye “memory leaks”.


Update: request to have InstantiateAndForgetIt Lifestyle natively supported issue IOC-225 (vote for it)

13 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. I think that Krzysztof Koźmic's solution http://bit.ly/akMznr using AutoReleaseInterceptor is more mature and will be enough for most cases

    ReplyDelete
  3. The reason why Windsor tracks Transient components is because those components may contain disposable dependencies (as in your example). In your example it may seem redundant to track the Transient component because the disposable dependency is a Singleton, so will never be disposed.

    However, consider another scenario where the dependency is another Transient component, but still disposable. In this case, if you don't track the outer component, you can't release it. That means that the inner component is never disposed.

    Hello "memory leak" :)

    In any case, there doesn't need to be any memory leaks. You just need to ensure that you invoked container.Release for every object graph created by container.Resolve.

    ReplyDelete
  4. @ploeh
    as you said "In your example it may seem redundant to track the Transient component because the disposable dependency is a Singleton, so will never be disposed."

    ReplyDelete
  5. If you change mysingleton to transient, or if you add a disposable transient dependency you must search all over the code for dependants and change then to Transient , InstantiateAndForget doesnt work anymore.
    Moreover, you will have to do major changes to your code to add a call to release.

    ReplyDelete
  6. @josé
    if my grandfather had 5 balls would be a pinball

    ReplyDelete
  7. To every body
    In .NET you have to know/check what is Disposable and what is not disposable.
    In Castle the interface ILifestyleManager inherith from IDisposable, why ?
    Because it is a contract and the consumer of ILifestyleManager will call Dispose even if the implementor of ILifestyleManager does not need to dispose anything.

    ReplyDelete
  8. @mookid
    Why you have removed your comment ? which was the problem ?

    ReplyDelete
  9. As self reminder
    http://www.springframework.net/doc-latest/reference/html/objects.html#objects-factory-scopes-prototype

    ReplyDelete
  10. Fabio, from your comments (especially the one to @ploeh) it looks like what you really want is http://issues.castleproject.org/issue/IOC-221

    And just a note - it's not true that "Singleton, [...] will never be disposed." It will be disposed when you dispose of the container.


    I won't repost my thoughts about this topic here, but I highly recommend that you read the following two posts:

    http://kozmic.pl/archive/2010/08/19/must-windsor-track-my-components.aspx
    http://kozmic.pl/archive/2010/08/27/must-i-release-everything-when-using-windsor.aspx

    About how Spring or StructureMap handle transients I believe the behavior to be flawed.

    ReplyDelete
  11. @fabio for me there are two completely differents things;
    a-To hold or not hold an instance in this case it is one thing.
    b-Doing a release of a transient component.

    You have described how to overcome A, but B is still a need, when resolving a transient instance through his interface with a factory I don't know if the implementation of the interface is disposable, of any of his dependencies is disposable (and has a transient lifestyle).

    Then, I have one problem with your code, having A without having B is like not having anything.. because if I need to do somehow a release of the component, I don't really care if the container keep for that short time a reference to my component.

    ReplyDelete
  12. @Krzysztof
    About the Singleton, I know and I'm sure you know that we dispose the container just before shutdown the application. In this case my observation is about the reason for which the life-cycle of a transient should be stuck to the to life-cycle of a singleton.

    ReplyDelete
  13. @jose
    If you have such kind of problem, that I don't, you have to use another lifestyle instead InstantiateAndForgetIt.

    ReplyDelete