Object pooling vs creating lots of them

If you, like me, have a background in C programming it's a spine reaction to avoid lots of memory allocations. So when you encounter a situation in managed code where you need to allocate lots of objects over time it feels natural to introduce a pool of objects. However I remembered reading somewhere that the .Net garbage collector is optimized for short lived objects so I started looking into this a little more.

Back to your C background; if you had to create lots of small objects on the fly in C you would either have a pool of objects or create your own memory management. Turns out that .Net essentially creates that custom memory management for you. Hence memory allocation is not so bad in .Net. At least not for objects that are not extremely large (since they are handled in a different way). The Garbage collector is also optimized for short lived objects. So I had to write a test.

My first test used a ConcurrentQueue into which I placed two test objects. I then started two threads that would take one object out of the queue, update a counter in the object and return it to the queue. Each thread did this in a loop until a total of 100 million loops were completed. On my double core laptop this took between eleven and twelve seconds to complete.

My second test also used two threads that would perform a total of 100 million loops and it would create the same test object as in the initial test, update the counter and the dispose the object. This took around three and a half second! Four times faster even though 100 million objects are allocated!

In my last test I created one object per thread and the thread just held on to this object until done. Running this test took just under two seconds.

I was surprised by the significant difference between allocations and using an object pool but also happy since any kind of pooling involves a lock which is always a bad sign. Also with a pool you typically need to clean or reinitialize your object before using it and you might forget to reset something at one point while with new objects they tend to be created fresh the way you want them. The only reason to actually pool objects would be if the object represents something that is expensive to setup. I only tested pooling versus allocation and if initial initialization takes significant time it might still be worth reusing objects.