Someone (Joshua) mentioned Ninject in the comments to in my IoC Benchmark. I hadn't heard of this project before but after checking out ninject.org and seeing the project slogan "lighning-fast dependency injection" I felt that it deserved be included in the test.

I am not sure what the slogan refers to though, lightning-fast usage and setup or runtime performance? Anyway it has a nice fluent registration API:

Bind<IUserRepository>()
  .To<LdapUserRepository>()
  .Using<SingletonBehavior>();
  
Bind<IAuthentificationService>()
  .To<DefaultAuthentificationService>()
  .Using<SingletonBehavior>();

Bind<UserController>()
  .ToSelf()
  .Using<SingletonBehavior>(); 

The tests were made with the release build of RC1 downloaded from the project homepage. I was kind of surprised by the results:

IoCSingleton_WithNinject
IoCTransient_WithNinject

I might be doing something wrong here but this is the result I got. For the transient case there seems to be a big memory leak. The Ninject kernel seems to keep references to transient objects. I tried the kernel's Release function but the memory leak was still evident.

Just to check that it was not something wrong with my code I did a profiling trace with JetBrains dotTrace:

NinjectTrace

It could still be me setting something up in the wrong way, but it looks like it's a bug in the Ninject Core.

Just a note: I think that doing premature optimization can result in bad design and architecture. The reason I did this and the previous test was not to find the fastest container, it was firstly to get a change to play with new (to me) containers, and secondly to see if there were any significant performance difference between them worthy of taking into account when choosing a container.

My conclusion in the previous test was that the difference in performance was not big enough to be relevant compared to other aspects of the containers, like how much you like the API or the features. The Ninject result for the transient test above is very significant, however it is probably caused by a memory bug in the release candidate and will likely be fixed in the next release. If you disregard this bug I actually kind of liked Ninject, it a had a nice API and a way of doing things, but it's slogan is currently a little misleading :)

For the complete code: IoCBenchmark_Revisited.zip

Updated (2008-05-05):

Nate Kohari has fixed the performance issue, the results are now inline with the other containers. For the new results (which also includes Autofac) please view this post.

4 comments:

Libor said...

Hi, when talking about IoC containers that you have not tested, do you know AutoFac - http://code.google.com/p/autofac/. Its a rather new IoC designed for C# 3.0.

Torkel Ödegaard said...

Yes I have heard of it, it looks intereseting.

There is also PicoContainer, i whish I could include every container but there are so many :)

Nate Kohari said...

Torkel, I have to thank you a lot for your original benchmark post. It made me dig further into the Ninject code, and realize some major deficiencies in terms of efficiency. The main problem was that I'd introduced a large amount of logging code that was executed whether or not logging was enabled.

Please try to re-run the benchmark with the trunk version of Ninject, and I think you'll see results more representative of the project's slogan. :) I ran the benchmark you developed, and for 500,000 instantiations, it was about 21% faster than Windsor, its nearest competitor. (I readily admit that Unity is still the fastest, though.)

This goes to show you that while the results of benchmarks might not matter in the long term, running them is still useful!

Torkel Ödegaard said...

That is great news Nate, I will try to update the post during the weekend.