TL;DR – A short and high-level explanation of object pooling technique with C#
Some of you may have noticed that i’ve been away for more than a month, but that was not without a reason. I decided that after almost 3 years at a start-up company it was my time to move on, and so after an intensive month of interviews i joined the Innovation Lab of a big corporation in the FinTech industry.
While going through countless interviews i encountered some very interesting questions that the interviewers had asked me. The most interesting one for my taste had to deal with object pooling in .NET.
The question went like this:
“Lets assume there is a limited number of instances of an object that is very expensive to construct. How would you go about creating an object pool in .NET? Meaning, some client code would request an instance, and you will need to provide a reference to an instance only when an instance is available in the pool.”
My immediate thought was, well, no problem! I shall incorporate some kind of reporting mechanism, so every client that finishes using an instance from the pool, he will have to release the object. Something like
My interviewer insisted:
“Well, a reporting mechanism is fine, but what if we want to make the system so robust that even when the client forgets to call ‘Release()’, the object will return to the pool and not get lost? “
Ok, so now the question became much more interesting.
Is there a way to implement such thing in .NET? Is there some convenient api?
Well, there isn’t. But…
Lets do a quick review on how the Garbage Collector works in .NET:
When an object with a destructor is allocated, the CLR stores a reference to that object in the internal CLR data structure called FinalizationQueue. When a garbage collection happens, the objects in the FinalizationQueue that are not in use anymore, are removed and then stored in another internal data structure called FReachableQueue. At that point a new thread is created in the system that is called “GC Finalizer Thread” whose only purpose in life is executing the destructor methods on all the objects in this queue.
(links for a further reading is at the end of the post)
We all know how to add a reference to a pool, right? Right, but what about the FinalizationQueue? How wonderful would this be if we could tell the Garbage Collector to return our object reference to the FinalizationQueue instead of freeing-up the memory and killing any remains of the object completely? Well, there is!
Returning an object back to the pool is simple and obvious, but telling the GC to return the reference to the FinalizationQueue is the essence of this article, and this should be incorporated in your object’s destructor:
What happens if you forget this invocation and simply return the reference back to the pool? Well, it will never get back to the Finalization-Queue, then the finalizer will not be invoked and then the reference will not get back to the pool after the first time because as far as the GC is concerned – your object does not have a destructor.
I find this trick pretty interesting, although i am still looking for a solution to a situation where garbage collection is not happening and a sort of a deadlock is happening when the application is waiting for a new instance in some sort of a while loop, and the pool is not getting back any objects because there is nothing triggering GC ro run.