Must I release everything when using Windsor?

This is a follow up to my previous post. If you haven’t yet – go and read that one first. I’ll wait.

So where were we? Aha…

In the last post I said, that Windsor (any container in general) creates objects for you, hence it owns them, ergo its responsibility is to properly end their lifetime when they’re no longer needed.

Since as I mentioned in my previous post, Windsor will track your component, it’s a common misconception held by users that in order to properly release all components they must call Release method on the container.

container.Release(myComponent);

How will Windsor know I no longer need an object?

That’s the most important part of this post really, so pay attention.

In Windsor (every container in general) every component has a lifestyle associated with it. In short lifestyle defines the context in which an instance should be reused. If you want to have just single instance of a component in the context of the container, you give the object a singleton lifestyle (which is the default in Windsor). If you want to reuse your object in the context of a web request, you give it a lifestyle of a per-web-request and so on. Now the word context (though overloaded) is important here.

When the context ends?

While some contexts, like web request have a well defined ends that Windsor can detect, that’s not the case for every of them. This brings us to the Release method.

Windsor has a Release method that you use to explicitly tell it “hey, I’m not gonna use this this object anymore.” Although the method is named very imperatively, which would suggest it takes immediate action, it’s not often the case. Quite a lot of time may pass between you call the method and Windsor will get the object destroyed. When the object gets really destroyed is up to its lifestyle manager, and they act differently.

  • Singleton will ignore your call to Release because the instance is global in the scope of the container that created it, and the fact that you don’t need the object in one place does not mean you won’t need it moments later somewhere else. The scope of the singleton lifestyle has a well defined end. Windsor will destroy the singletons when the container itself is being disposed. This also means that you don’t have to Release your singletons – disposing of the container will take care of that.
  • Per-web-request will ignore your call to Release for similar reasons – the object is global in the scope of a web-request. Web request also has a well defined end, so it will wait with destroying the object till the end of the web request and then do all the work necessary. This also means that you don’t have to release your per-web-request components – Windsor can detect end of a web request and release the per-web-request components without and intervention from your side.
  • Per-thread is like singleton in the scope of a thread. Releasing Per-thread components does nothing, they will be released when the container is disposed. This means that in this case as well you don’t have to do anything explicitly about them (except for remembering to dispose the container obviously) ..
  • Pooled components are different. They don’t really have a well defined “end”  so you need to return a component to the pool explicitly (that is pass them to container’s Release method), and Windsor (depending on the component and configuration of the pool) may either return the object to the pool, recycle it, or destroy and let it go. Thing is - it matters, and it usually makes sense to return the object to the pool, as soon as possible (think connection pooling in ADO.NET).
  • Transient components are similar to pooled, because there’s no well known end to transient component’s lifetime, and Windsor will not know if you still want to use a component or not, unless you explicitly tell it (by calling Release). Since transient components are by definition non-shared Windsor will immediately destroy the component when you Release it.

And then it gets interesting

If you’re now scratching your head thinking “Does Windsor really puts all the burden of releasing stuff on me?” don’t despair. The reality is – you never have to call Release explicitly in your application code. Here’s why.

You never have to call Release…

Releasing a component releases entire graph. As outlined in previous section, Windsor can detect end of scope for components with most lifetimes. In that case, if you have a per-web-request ShoppingCard component that depends on transient PaymentCalculationService and singleton AuditWriter, when the request ends Windsor will release the shopping card along with both of its dependencies. Since auditwriter is a singleton releasing it will not have any effect (which is what we want) but the transient payment calculator will be releases without you having to do anything explicitly.

You obviously need to structure your application properly for this to work. If you’re abusing the container as service locator than you’re cutting a branch you’re sitting on.

Explicitly…

This also works with typed factories – when a factory is released, all the components that you pulled via the factory will be released as well. However you need to be cautious here – if you’re expecting to be pulling many components during factory’s lifetime (especially if the factory is a singleton) you may end up needlessly holding on to the components for much too long, causing a memory leak.

Imagine you’re writing a web browser, and you have a TabFactory, that creates tabs to display in your browser. The factory would be a singleton in your application, but the tabs it produces would be transient – user can open many tabs, then close them, then open some more, and close them as well. Being a web savvy person you probably know firsthand how quickly memory consumption in a web browser can go up so you certainly don’t want to wait until you dispose of your container to release the factory and release all the tabs it ever created, even the ones that were closed days ago.

More likely you’d want to tell Windsor to release your transient tabs as soon as the user closes it. Easy – just make sure your TabFactory has a releasing method that you call when the tab is closed. The important piece here is that you’d be calling a method on a factory interface that is part of your application code, not method on the container (well – ultimately that will be the result, but you don’t do this explicitly).

UPDATE:

As Mark pointed out in the comment there are certain low level components that act as factories for the root object in our application (IControllerFactory in MVC, IInstanceProvider in WCF etc). If you’re not using typed factories to provide these service and implement them manually pulling stuff from the container, than the other rule (discussed below) applies - release anything you explicitly resolve

In your application code

There are places where you do need to call Release explicitly – in code that extends or modifies the container. For example if you’re using a factory method to create a component by resolving another component first, you should release the other component.

container.Register(
   Component.For<ITaxCalculator>()
      .UsingFactoryMethod(
      k =>
      {
         var country = k.Resolve<ICountry>(user.CountryCode);
         var taxCalculator = country.GetTaxCalculator();
         k.ReleaseComponent(country);
         return taxCalculator;
      }
      )
   );

This is a code you could place in one of your installers. It is completely artificial but that’s not the point. Point is, we’re using a factory method to provide instances of a component (tax calculator) and for this we’re using another component (country). Remember the rule – You have to release anything you explicitly resolve. We did resolve the country, so unless we are sure that the country is and always will be a singleton or have one of the other self-releasing lifestyles, we should release it before returning the tax calculator.


Posted 08-27-2010 3:52 AM by Krzysztof Koźmic
Filed under: , ,

[Advertisement]

Comments

TrackBack wrote Twitter Trackbacks
on 08-27-2010 11:06 AM
Kelly Brownsberger wrote re: Must I release everything when using Windsor?
on 08-31-2010 6:42 AM

Hey Krzysztof - thanks for the post.

I'm curious if the per-web-request is smart enough to be aware of WCF operation context?  I'm sure this works well for ASP.NET runtime context (i.e. http context), but can I assume it handle the WCF runtime as well?

Simon wrote re: Must I release everything when using Windsor?
on 08-31-2010 11:56 AM

What is the recommended pattern for Windows Form/WPF applications where you may have tabs being opened and closed. How do you allow the objects that live under these tabs/forms to be garbage collected?

Krzysztof Koźmic wrote re: Must I release everything when using Windsor?
on 09-01-2010 10:14 AM

@Kelly,

No, Per web request handles web requests, WCF Facility has per-wcf-operation lifetime that does similar thing in the scope of WCF operation request stw.castleproject.org/Windsor.WCF-Facility-Lifestyles.ashx

@Simon

have  a look at the sample Silverlight app for Windsor.

Simon wrote re: Must I release everything when using Windsor?
on 09-01-2010 4:14 PM

Hi - I'm probably missing something obvious, but in the Silverlight sample, I can only see that the container gets cleaned up when the app shuts down.

How can we deal with the situation where you have lots of services/objects configured with transient lifestyle but you want to release them when tabs or sub windows are closed.

Thanks Krzysztof.

Simon

Krzysztof Koźmic wrote re: Must I release everything when using Windsor?
on 09-01-2010 5:37 PM

Simon see this:

github.com/.../MainView.xaml.cs

(view)Models are transient, when you're setting a new one (which de facto means changing current screen) you're closing current one first, and releasing it back to Windsor. Like I said in the post, that's done via TypedFactory

Cheers

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)