Avoiding Memory Leaks With NServiceBus And Your Own Castle Windsor Instance
Posted by Davy Brion on February 19th, 2010
If you’re using NServiceBus together with your own instance of Castle Windsor, there is one thing you really need to look out for. NServiceBus was originally developed with Spring.NET as its IoC container, but it’s been changed to support multiple containers in a similar manner as Agatha does it. Agatha however, was originally developed with Castle Windsor as its IoC container, and as such is well aware of Windsor’s need to explicitly release resolved components. NServiceBus unfortunately was not aware of this need, and a workaround that they have introduced is to set Windsor’s ReleasePolicy to the NoTrackingReleasePolicy (which doesn’t hold any instances in memory, but doesn’t provide any cleanup either) if you configure NServiceBus to use its own instance of Castle Windsor. However, if you’re integrating NServiceBus into a project that is already using Castle Windsor, then you probably want NServiceBus to use your instance of Castle Windsor.
And that is when problems might appear. If you’re using Castle Windsor with the default ReleasePolicy (which is the LifecycledComponentsReleasePolicy) then each resolved transient instance will be stored in memory by that policy until the instance is explicitly released. The benefit of this policy is that the container can automatically dispose any disposable transient dependency of a resolved component. In my case, i’ve come to rely on that feature to achieve deterministic disposal behavior throughout my code base.
Now, when you configure NServiceBus and pass it your instance of Castle Windsor, it obviously doesn’t change the ReleasePolicy like it does when it creates its own instance of Castle Windsor. This is good because changing the policy of a passed in container would almost certainly have a huge behavioral implication for the application and such an action would be unacceptable when integrating a new framework into your project. But since NServiceBus doesn’t have the notion of needing to release resolved components, every single transient instance it resolves through your container will be stored in memory until the application’s process is terminated. Which means that you’ll leak instances of the following types for each message that your system needs to handle:
- NServiceBus.Grid.MessageHandlers.GridInterceptingMessageHandler
- NServiceBus.Sagas.Impl.SagaMessageHandler
- Your own MessageHandlers (and their transient dependencies as well)
If your MessageHandlers don’t have dependencies (highly unlikely if you’re already using an IOC container) then you’d still have 3 leaking instances per incoming message. Add the number of transient dependencies of any handler to that and the number of leaking instances can increase dramatically.
First of all, if you do not depend on Windsor’s default ReleasePolicy’s behavior, then the easiest way to avoid this problem is definitely to set the container’s ReleasePolicy to the NoTrackingReleasePolicy like NServiceBus does itself when it’s configuring itself with a new instance of the container.
If you do depend on it, and you don’t want leaking instances that hang around forever, then the approach listed below is one way to solve this problem. There are probably other solutions available, and while the approach listed below can definitely be considered to be a HACK, i do think it’s the best solution to this particular problem.
Because we don’t want to change anything about the way that we’re already using the container, we just need to make sure that NServiceBus’ usage of the container doesn’t conflict with ours. That basically means that we need to make sure that the components that it resolves should not be tracked by the container. There are 2 kinds of components that NServiceBus will resolve during normal operation:
- Its own components that it needs to implement the features it offers you
- Your message handlers that you need to handle incoming messages
The first category is easy to exclude from Windsor’s tracking behavior. We can simply create our own ReleasePolicy which extends the default ReleasePolicy, and make sure that any instances of an NServiceBus-type are no longer tracked by the container:
public class MyReleasePolicy : Castle.MicroKernel.Releasers.LifecycledComponentsReleasePolicy
{
public override void Track(object instance, Castle.MicroKernel.Burden burden)
{
if (!instance.GetType().FullName.StartsWith("NServiceBus"))
{
base.Track(instance, burden);
}
}
}
Then you need to set this release policy somewhere in your application’s startup routine:
IoC.Container.Kernel.ReleasePolicy = new MyReleasePolicy();
(in this case, IoC.Container returns an IWindsorContainer instance)
This will make sure that no instances of NServiceBus-types will ever leak in the container. But now we still have to deal with our message handlers. The solution to making sure they are not disposed is not the cleanest out there but hey, it works. I basically introduced a base class that all my message handlers will need to inherit from, with the following implementation in the Handle method:
public abstract class MessageHandler<TMessage> : IMessageHandler<TMessage> where TMessage : IMessage
{
public void Handle(TMessage message)
{
try
{
Process(message);
}
finally
{
// ugly as hell, but we need this until NSB releases its resolved components
IoC.Container.Release(this);
}
}
protected abstract void Process(TMessage message);
}
Uh oh… i just felt a great disturbance in the Force, as if tens of voices suddenly cried out in terror about my direct usage of the IoC container in a component!
Conceptually, this is wrong on many levels. Then again, this makes sure that the message handlers (and their dependencies) that are resolved by NServiceBus will always be guaranteed to be released by the comtainer. It might not be nice, but it avoids the memory leak and it doesn’t force me to change my other code.
And once NServiceBus is modified to release the components it resolves (if it’s ever modified that is…) i only need to get rid of my custom policy and the try/finally block. Unfortunately, my existing message handlers will then all implement the Process method instead of the Handle method but that is quickly fixed with a simple rename-refactoring.
Even though this is a pretty big hack (IMHO), at least its impact on the code is minimal… it will be easy to get rid of once the real problem is solved in NSB, and there are no real downsides to this that i can think of at the moment.

February 21st, 2010 at 9:25 pm
Now, when you configure NServiceBus and pass it your instance of Castle Windsor, it obviously doesn’t change the ReleasePolicy like it does when it creates its own instance of Castle Windsor.
Well, it actually does. The relevant part in WindsorObjectBuilder class is
public WindsorObjectBuilder(IWindsorContainer container)
{
Container = container;
container.Kernel.ReleasePolicy = new NoTrackingReleasePolicy();
}
and it is called from ConfigureWindsorBuilder
public static Configure CastleWindsorBuilder(this Configure config, IWindsorContainer container)
{
ConfigureCommon.With(config, new WindsorObjectBuilder(container));
return config;
}
February 21st, 2010 at 9:30 pm
huh, that’s weird… i tested it before using my own release policy and the kernel’s ReleasePolicy was still set to the default after configuring NSB. I’m probably still using a build from right before the NoTrackingReleasePolicy-change was made to NSB…
Either way, the approach above will still work, as long as you overwrite the ReleasePolicy _after_ you configure NSB.
I do think the act of changing the ReleasePolicy of a passed-in container to the NoTrackingReleasePolicy is wrong… the consequences it can have on existing code can be pretty big and people really need to be aware of this
February 21st, 2010 at 9:41 pm
I totally agree, it should not change the container handed to it.
You have quite a neat solution here. So far I went along with NSB’s behaviour in my app, because I don’t have my own code that would rely on this feature of Windsor, but I think I will switch to your solution – even if I don’t rely on it one never knows if some other stuff (like facilities) also does not.
Thanks for sharing it.
BTW I would change the check to catch NSB namespace only:
if (!instance.GetType().FullName.StartsWith(“NServiceBus.”))
February 22nd, 2010 at 10:14 am
that is interesting.
Can’t NServiceBus limit scope of container by using nested container per unit of work?
This may be my motivation to finally take a look at NSB, which I’ve been meaning to do for quite some time.
February 22nd, 2010 at 10:15 am
@Krzysztof
you’d have to ask Udi that… though i suspect he’ll tell you that the NoTrackingReleasePolicy is already “good enough”
February 22nd, 2010 at 10:56 am
@Davy
It obviously is not.
).
NTRP fixes symptoms – not causes.
You may use no IoC Container at all, and still NSB not releasing it’s components means you will have leaks nonetheless. You may have handlers that obtain database connection. If you don’t release them, they won’t release the connection. They may have finalizers but before finalizers run, you may already be out of connections and your application may die (yes – there are more problems here than these related to NSB, but it’s just an example
And that problem would touch not only Windsor. AutoFac also tracks some transient components, StructureMap does so with nested containers… dunno about the rest.
February 22nd, 2010 at 11:28 am
You’re right that NServiceBus shouldn’t change the release policy of the container that is passed in – this will be fixed in the 2.0 RTM.
February 22nd, 2010 at 11:29 am
@Krzysztof
i’m not the one you need to convince here… most people think i take IDisposable and memory management in general too seriously
)
(coincidentally, these are the same people who don’t believe me when i say we always disable application pool recycling and _don’t_ run into issues with it… go figure
March 11th, 2010 at 9:14 pm
[...] actually, and while I have precisely zero knowledge of NServiceBus, I think it could be used to fix the issue Davy discussed, without having to mess with release policy. Posted 03-11-2010 9:13 PM by Krzysztof Koźmic Filed [...]