Question

I'm trying to use Ninject (version 3.0.1) in a WinForms application, I have several (currently) self-binded service class, which I construct using Ninject. Some service class needs other service classes (sub-services). Most of these service classes need a repository to interact with the database, for what I have an abstract IRepository interface. I need to have the same repository for the whole service-hierarchy in a service class, so I'm using the InCallScope() scope when binding the IRepository. Currently I'm using XPO as an ORM tool, so I have an XpoRepository implementation, which I'm binding to. See my other question about this scenario.

My binding looks like this:

Bind<IRepository>().To<XpoRepository>().InCallScope();

I don't have explicit ToSelf() bindings for each service class, so I assume when I get them from Ninject, they should have the transient scope, which I interpret as I have to manually dispose them.

Assume that I have a Services1 and a Services2 service class, both having a constructor parameter of type IRepository. Now assume that Services1 would like to use some methods of Services2, so I add another constructor parameter to Services1 with type Services2. Without Ninject, I would do:

var repo = new MyRepository(); // implementing IRepository
var service1 = new Services1(repo, new Services2(repo));

I'm using one of the services in a background thread (using TPL), in a loop like this:

while (true) {
    if (CancellatioPending())
        break;
    using (var service = _kernel.Get<Service1>())
    {
        // do some stuff using the service class
    }
    Thread.Sleep(20*1000);
}

I had the same structure before using Ninject, so I have (I think) properly implemented disposal of every objects, including repositories in the correct places. However, I've noticed that since I'm utilizing Ninject for this, I have a big memory leak in my application, and it crashes in every 2-3 hours with OutOfMemoryException. I put a breakpoint inside the loop, and noticed that the Ninject cache has thousands of entries full of disposed XpoRepository objects. They are disposed by me I guess, but I'm not sure who called the dispose method.

Why is Ninject holding these disposed objects? I would expect that when I dispose the main service in the end of the using block (which is the scope of the IRepository objects due to InCallScope()) every object in its scope should be disposed and released by Ninject.

EDIT: Before any comment or answer about why this pattern is not good, I know that it could be better. I know I could extract service interfaces to actually make use of DI and improve testability, and I also know that I should probably use a Func<IRepository> as a constructor parameter, and inject into it, and like that every service could have its own reponsibility to dispose the repository. Simply I have no time for such refactorings currently.

Was it helpful?

Solution

Ninject will release the repository if all the following things are true:

  • no one is holding a reference to service1
  • service1 itself is GC'd (since you have a thread sleep of 20 sec there is a high chance that it has been promoted to Gen 2 and they are released very rarely)
  • Cache pruning was executed after service1 is GC'd, The cache pruning interval defaults to 30 sec. You may want to try a shorter interval.
  • Alternatively to the previous point you can try to force immediate releasing by implementing Ninject.Infrastructure.Disposal.INotifyWhenDisposed in service1
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top