We ran into a huge memory leak this week. A bit of memory profiling with JetBrains’ dotTrace quickly showed that the Windsor IoC container was holding on to a lot of references. It turned out that i actually forgot to release the components i was requesting Windsor to construct for me. I use the container in my web-layer to compose every page’s Controller with its dependencies. And in my service layer, i use the container to compose every RequestHandler and its dependencies. So that’s two instances of the Container, in two separate AppDomains, and both are leaking a lot of memory due to my mistake.
My mistake was that after i was done with the components that i asked Windsor to resolve, i simply disposed them (which in turn would dispose their dependencies) and i figured that would be enough, since my components are registered as Transient. That means that each time you request a Transient component, you get a new instance. This led me to believe that Windsor wouldn’t need to hold a reference to the constructed components so i figured that simply disposing them would be enough, since they are IDisposables. Disposing them is a good thing obviously, but because the container was still holding references to the requested components, that’s still a lot of memory that is being wasted because even though you’ve disposed them, they aren’t eligible for Garbage Collection until they are no longer accessible. And because the container kept references to them, they remained accessible and were never collected. And there was my memory leak. Oops.
In order to prevent this problem in the future for myself and anyone else who reads this, let’s go over a few examples which should make it clear how you should make sure that your components are properly released so they are eligible for garbage collection.
Let’s start really simple. We have an IController interface and a simple Controller class which implements the IController interface:
public interface IController : IDisposable
{
bool Disposed { get; set; }
}
public class Controller : IController
{
public void Dispose()
{
Disposed = true;
}
public bool Disposed { get; set; }
}
In our tests, we’ll use the following method to create and configure the container:
private WindsorContainer CreateContainer()
{
var container = new WindsorContainer();
container.Register(Component.For<IController>().ImplementedBy<Controller>().LifeStyle.Transient);
return container;
}
The IController interface is registered with the container, and the container will return a new Controller instance (because of the Transient lifestyle) whenever someone requests an IController instance.
The following test highlights the memory leak that i was experiencing:
[Test]
public void ContainerKeepsReferenceToControllerIfWeOnlyDisposeOfIt()
{
var container = CreateContainer();
var controller = container.Resolve<IController>();
Assert.That(container.Kernel.ReleasePolicy.HasTrack(controller));
controller.Dispose();
Assert.IsTrue(controller.Disposed);
// the controller is disposed of, but the container is still keeping track
// of the instance
Assert.That(container.Kernel.ReleasePolicy.HasTrack(controller));
}
When you request a component from the Container, it keeps a reference to that instance in its Kernel’s ReleasePolicy object. If you merely dispose of your requested component, the ReleasePolicy still holds the reference to the component. This is what caused my memory leak.
So how do we avoid this problem? It’s pretty easy actually:
[Test]
public void ContainerDoesNotKeepReferenceToControllerIfWeReleaseIt()
{
var container = CreateContainer();
var controller = container.Resolve<IController>();
Assert.That(container.Kernel.ReleasePolicy.HasTrack(controller));
// instead of disposing the controller, we'll Release it through the container
container.Release(controller);
Assert.IsTrue(controller.Disposed);
// the controller is disposed of, and the container is no longer keeping
// track of the instance
Assert.IsFalse(container.Kernel.ReleasePolicy.HasTrack(controller));
}
Instead of just disposing our controller, we tell the container to release it. The container in turn knows that because IController inherits from IDisposable, it should dispose the Controller instance. It also removes the instance from its Kernel’s ReleasePolicy object and once your own reference to the Controller instance goes out of scope, it’s eligible to be collected by the Garbage Collector.
As you can see, it’s very easy to make sure your components are properly released and eligible for garbage collection. But what about possible dependencies of your components? Let’s take a look.
Suppose we define the following interface and implementation:
public interface IDependency { }
public class MyDependency : IDependency { }
The dependency doesn’t actually do anything, but bear with me 🙂
We modify the IController interface and Controller implementation like this:
public interface IController : IDisposable
{
bool Disposed { get; set; }
IDependency Dependency { get; }
}
public class Controller : IController
{
public IDependency Dependency { get; private set; }
public Controller(IDependency myDependency)
{
Dependency = myDependency;
}
public void Dispose()
{
Disposed = true;
}
public bool Disposed { get; set; }
}
And then we modify the configuration of the container like this:
private WindsorContainer CreateContainer()
{
var container = new WindsorContainer();
container.Register(Component.For<IController>().ImplementedBy<Controller>().LifeStyle.Transient);
container.Register(Component.For<IDependency>().ImplementedBy<MyDependency>().LifeStyle.Transient);
return container;
}
Whenever we request an IController instance, the container will construct a Controller instance and will pass a MyDependency instance to the Controller’s instance constructor. The question now is: does the container also track the instances of a requested component’s dependencies? The answer is: no
[Test]
public void ContainerDoesNotKeepReferenceToControllersDependencies()
{
var container = CreateContainer();
var controller = container.Resolve<IController>();
Assert.That(container.Kernel.ReleasePolicy.HasTrack(controller));
Assert.IsFalse(container.Kernel.ReleasePolicy.HasTrack(controller.Dependency));
}
We request an IController instance, which is tracked by the container. The IController’s Dependency property contains an IDependency instance, which was also created by the container. But as the last line of the test shows: the container does not track instances of the requested IController’s dependencies.
So what does that mean? If the dependencies don’t require any cleanup, then this is great. We simply need to release the requested component, and the component and its dependencies will all be eligible for Garbage Collection. But what happens when the dependencies need to be disposed? Let’s take another look.
We modify the IDependency interface and MyDependency class so it looks like this:
public interface IDependency : IDisposable
{
bool Disposed { get; set; }
}
public class MyDependency : IDependency
{
public bool Disposed { get; set; }
public void Dispose()
{
Disposed = true;
}
}
Now let’s see what happens with the Controller’s dependencies when we release the Controller:
[Test]
public void ContainerDoesNotDisposeControllersDisposableDependencies()
{
var container = CreateContainer();
var controller = container.Resolve<IController>();
var dependency = controller.Dependency;
Assert.That(container.Kernel.ReleasePolicy.HasTrack(controller));
container.Release(controller);
Assert.IsFalse(container.Kernel.ReleasePolicy.HasTrack(controller));
Assert.IsFalse(container.Kernel.ReleasePolicy.HasTrack(dependency));
Assert.IsTrue(controller.Disposed);
Assert.IsFalse(dependency.Disposed);
}
The container holds no references, but the Controller’s Dependency instance is not disposed! Notice however that the Controller has been disposed by the container. As i’ve mentioned earlier, if you own a reference to an IDisposable instance, you are responsible for properly disposing of that instance. So we modify the Controller’s Dispose method so that it looks like this:
public void Dispose()
{
Dependency.Dispose();
Disposed = true;
}
The previous test will now fail, because the Dependency will be properly disposed.
NOTE: i certainly don’t recommend to implement your Dispose methods like i just did. This is just a simplified example. The proper way to implement the Disposable Pattern is discussed here.
Anyways, i hope it’s clear now how you can make sure your IoC usage does not cause memory leaks, and that everything is properly disposed of.
This seems like something that shouldn’t be your responsibility. It would be nice if there was a LifeCycle that told Windsor to use a WeakReference for keeping track of things so they could be collected properly.
So where did you finally put that container.Release(controller) statement? Having that in your tests in nice but it certainly did not fix your memory leak, right? I’m just concerned with who needs to know about the container and the controller at the same time.
Sergio: well the tests were just an example to highlight the problem and the solution. In the real application code, i ask the container for an instance of the correct controller in the constructor of my base asp.net page. Then when the Dispose method of that base page is called, i release it again.
As for my service layer, i request an instance of the correct RequestHandler, i delegate to that handler and right after that i call release it.
and that did fix the memory leak
So Controller is responsible for disposing of something it did not explicitly create? That’s a little presumptuous isn’t it?
> if you own a reference to an IDisposable instance, you are responsible for properly disposing of that instance.
I agree (and I’ve read your other article). However, in this case, Controller clearly does not own its dependency.