Tag Archives: garbage collection

Using IDisposable with Autofac

Using IDisposable with Autofac presents a few challenges and requires you to really think about lifetime scopes to avoid memory leaks. These days, with pretty excellent garbage collection built into .NET the age-old process of finding memory leaks is usually something that you need not worry about anymore. However, the contract of an IDisposable is something that still requires manual release. And if you’re ever resolving anything deriving from IDisposable using Autofac you’re going to run into problems.

Take a look at this code. What does it do?

using System;
using Autofac;

namespace AutoFacDisposableDemo
{
    public interface IResource : IDisposable 
    {
    }

    public class MyResource : IResource
    {
        private byte[] _lotsOfMemory;

        public MyResource()
        {
            _lotsOfMemory = new byte[1000000];
        }

        public void Dispose()
        {
            _lotsOfMemory = null;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<MyResource>().As<IResource>();
            var container = builder.Build();

            while (true)
            {
                using (container.Resolve<IResource>())
                {
                }
            }
        }
    }
}

At a first glance, it seems to do nothing but feed the garbage collector. But take a look at the memory usage. It will be constantly increasing, and you will run out of memory! If you try removing the IDisposable interface from the IMyResource this code will stop running out of memory. So why does this happen?

Autofac manages your IDisposables

Yes, Autofac tries to be smart and will actually contain a reference to the object internally whenever you resolve a component that is deriving from IDisposable. This is because autofac doesn’t know what other objects might be referencing your resource and you haven’t told it anything on when it is supposed to go out of scope. Especially if autofac is wired in such a way to create non-transient instances where many could be using your disposable object and only the last usage should dispose of it.

This happens transparently, and because you’ve normally done what is usually the right thing and called Dispose on it, you have released the expensive resources on it – leaving only a small skeleton object floating around that never will be garbage collected. This is scary because the memory leak isn’t huge and obvious like forgetting to dispose of sockets that show up pretty quickly. If you run this through a memory profiler it will be held by some internal IDisposable stack somewhere that is rooted to a closure somewhere deep down.

It really is not a solution to try to work around this by removing the from the interface, since that will cause all sorts of problems down the road – breaking the semantics in the processs. Instead what you need to do is to use lifetime scopes. If you change the main loop to this it will run without a leak:

while (true)
{
    using (var scope = container.BeginLifetimeScope())
    {
       var myResource = scope.Resolve<IResource>();
    }
}

Note that we are resolving from the opened scope, and disposing the scope instead of the allocated resources. This is all fine but a bit simplistic. What happens if we are using factory functions instead?

public interface IResourceFactory
{
    IResource GetResource();
}

public class MyResourceFactory : IResourceFactory
{
    private readonly Func<IResource> _newResource;

    public MyResourceFactory(Func<IResource> newResource)
    {
        _newResource = newResource;
    }

    public IResource GetResource()
    {
        return _newResource();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MyResource>().As<IResource>();
        builder.RegisterType<MyResourceFactory>().As<IResourceFactory>();
        var container = builder.Build();

        var factory = container.Resolve<IResourceFactory>();

        while (true)
        {
            using (var scope = container.BeginLifetimeScope())
            {
                var myResource = factory.GetResource();
            }
        }
    }
}

Out of memory again. Autofac will give you a Func that does new for you in a sense. But that Func is dynamically created to make objects that have the same lifetime scope as the factory object – not the lifetime scope that you called it in! This makes prefect sense in a way, since you can have multiple lifetime scopes going on at the same time – even nested since you can create a lifetime scope from another lifetime scope. Changing it to this will eliminate the problem:

class Program
{
    static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MyResource>().As<IResource>();
        builder.RegisterType<MyResourceFactory>().As<IResourceFactory>();
        var container = builder.Build();

        while (true)
        {
            using (var scope = container.BeginLifetimeScope())
            {
                var factory = scope.Resolve<IResourceFactory>();
                var myResource = factory.GetResource();
            }
        }
    }
}

Singletons

Ah, the global variables of the 21st century. What happens if you make the resource factory into a singleton?

var builder = new ContainerBuilder();
builder.RegisterType<MyResource>().As<IResource>();
builder.RegisterType<MyResourceFactory>().As<IResourceFactory>().SingleInstance();
var container = builder.Build();

Bam. Out of memory again! Singletons might be better than globals, but it’s still not a very good idea. The func will be bound to the top lifetime scope and all the IDisposables that gets created are also bound to that scope regardless of how many times you call Dispose on them. A better idea would be to use InstancePerLifetimeScope instead. This removes the problem but also causes the factory to be instantiated several times. Singletons are generally a bad idea, since you can’t be sure who is going to be adding a dependency on an IDisposable and cause memory or resource leak.

More options

There is a Owned class that you can resolve for. So, if you resolve for Owned instead, you are required to release the resource yourself and autofac does no effort to keep the reference in memory any more. Just make sure you call Dispose on the Owned object instead of the internal IResource.

Creating lifetime scopes

You don’t want to pass your scopes around, so you can get the lifetime scope injected for you if you take a dependency on the LifetimeScope object. If you do so, the current lifetime scope from the Resolve will be passed to the constructor from which you can derive more child lifetime scopes or Resolve objects given the current scope. It leaves a bad taste since this has all the trademarks of showing your container since the scope will allow you to create any instance of any type without making an explicit dependency. It would be a better solution to try to avoid this and rely on auto-generated Funcs to create objects in the correct lifetime scope.

In conclusion

  • Be really careful. The leaks are not obvious, and if you’re using other peoples code to inject you can never be sure when they’re using something that is disposable.
  • If you’re using factories, they cannot be singletons if used to create anything IDisposable. In fact, I’d avoid them in general since it’s way too easy to pass a factory from a different scope into a child scope and using that to create objects that will be leaking.
  • Find distinct units-of-work and begin and end lifetime scopes there. This is the place to resolve objects that are all in the same scope.
  • Don’t dispose of injected IDisposables manually. If you work with autofac instead of against it the objects should dispose of them for you. This makes you safe for whenever someone decides to add another usage of your object or change the number of instances created. If you absolutely need to dispose of it manually – make use of the Owned class, and get an object that you yourself are responsible for.
Tagged , , , ,