views:

501

answers:

4

I have an ASP.NET MVC app that creates a Linq2SQL datacontext on a per-web-request basis using Castler Windsor IoC.

For some reason that I do not fully understand, every time a new datacontext is created (on every web request) about 8k of memory is taken up and not released - which inevitably causes an OutOfMemory exception.

If I force garbage collection the memory is released OK.

My datacontext class is very simple:

 public class DataContextAccessor : IDataContextAccessor
 {
    private readonly DataContext dataContext;
    public DataContextAccessor(string connectionString)
    {
        dataContext = new DataContext(connectionString);           
    }
    public DataContext DataContext { get { return dataContext; } }
 }

The Windsor IoC webconfig to instantiate this looks like so:

 <component id="DataContextAccessor"
             service="DomainModel.Repositories.IDataContextAccessor, DomainModel"
             type="DomainModel.Repositories.DataContextAccessor, DomainModel"
             lifestyle="PerWebRequest">       
    <parameters>
      <connectionString>
        ...
      </connectionString>
    </parameters>
  </component>

Does anyone know what the problem is, and how to fix it?

+5  A: 

L2S DataContext implements IDisposable. Your interface also has to implement it, and call DataContext.Dispose(), so that Windsor knows that there're resources to be disposed.

By the way beware of Windsor/IDisposable problems: http://www.jeremyskinner.co.uk/2008/05/03/aspnet-mvc-controllers-windsor-and-idisposable/ http://www.nablasoft.com/Alkampfer/?p=105

queen3
+3  A: 

From what I can tell, queen3 is correct, your DataContextAccessor class needs to implement IDisposable and call datacontext.Dispose() from its .Dispose() method. (Disclaimer: I haven't worked with Castle Windsor.)

Alternatively, what I would do is turn your DataContextAccessor into a DataContextFactory, which only creates the DataContext when you call a method (e.g. GetContext()). Then you can do this:

using(DataContext context = myDataContextFactory.GetContext()) {
    // Do whatever you want with the context
}
// Context is disposed here

You might also want to take a look at this previous question: How do you reconcile IDisposable and IoC?

Daniel Pryden
+1  A: 

No your DataContextAccessor does not need to implement IDisposable. Windsor is smart enough to handle the case without having to do any modifications to your classes.

However since as noted in the other answers DataContext does implement it, and Windsor sees it and it registers it for cleanup (to call the Dispose method on it).

What you need to do is to call container.Release and pass your root service (which probably would be DataContextAccessor in your case). Windsor will then release it and all its dependencies (it will also call Dispose on DataContext) and the memory will be freed.

If you're using ASP.NET MVC consider using MVCContrib project which has Windsor integration that handles releasing of components for you.

Krzysztof Koźmic
A: 

I think @Krzysztof Koźmic is right... you should release whatever you get from Windsor.

Windsor is pretty alien to anyone used to IDisposable. The reason for this apparent disparity is down to the management of the component's lifecycle. If you take a component from Windsor that is IDisposable, you don't know if that instance is configured as transient or a singleton (and of course this could change as your app evolves).

If you dispose a component and it later turns out to be a singleton, some other client code is going to be wondering why its component has suddenly failed!?! Only Windsor is able to make the Disposal decision for you.

Nice blog post Krzysztof (won't let me post link!)

In our app we've made everything transient, apart from a couple of singletons. Transient seems to be the simplest model (as long as everyone understands you must 'Release rather than Dispose'). If you have a mock container in your tests, you can set an expectation that Release is called for each component your mock resolves, and I've also heard that transient has fewer performance issues (??) than other modes? The code is certainly more portable.

Last but not least, if you have a memory leak and you need to work what and why something isn't being collected by the GC, check out Tess Ferrandez' fab tutorial series on windbg http://blogs.msdn.com/b/tess/archive/2008/04/03/net-debugging-demos-lab-7-memory-leak-review.aspx ... the culprit may be somewhere unexpected!