Object Pool Pattern

Classic GOF Constructional Design Patterns

 
  

Intent

In very simple term, this design pattern means To Reuse objects which are very costly to create. Object pooling is creating objects of the class at the time of creation and put them into one common pool. Now whenever application needs object of that class instead of instantiating new object we will return the object from the object pool. Once the task is completed the object will be return back to the pool.

This pattern is very common when you desire: performance or need the ability to limit the number of critical resources.

object pool patterns
  

Problem

When building applications, you often come across objects that are either expensive to create or need to be limited to some number above one (1). In some scenarios, the cost of creating new objects is high enough to impact application performance. This is where the object pool design pattern comes to the rescue.

  

Discussion

The object pool design pattern is used to recycle objects rather than recreate them each time the application needs them. By keeping reusable instances of objects in a resource pool, and doling them out as needed, this pattern helps to minimize the overhead of initializing, instantiating, and disposing of objects and to boost the performance of your application. This is also beneficial in scenarios where it is desired to maintain no more than a specific number of instances of an object around at a time.

When the application requests an object, and the object is available from the pool, it is returned from the pool. If the object of the requested type is not available from the pool, then a new instance of the object is created and returned. When the application no longer needs the object, the object is sent back to the pool.

The minimum and maximum number of objects that an object pool can hold is configurable. If the application needs an object from the pool but the maximum number of objects has been allocated, a typical custom object pool implementation can adopt one or more of the following strategies:

  • Return null or throw an exception
  • Block the call until an object is available
  • Increase the pool size to accommodate more objects

An object pool is very similar to a database connection or thread pools. Just as the connection pool controls the maximum number of connections to the database, the object pool controls the number of class instances that the application will use.

One of the key factors when using object pools is that the pool itself MUST account for resetting all returned objects to some pre-defined state. Without this, we can run into objects that have the wrong state or contain information left over from its last use. It is CRITICALLY important that the object pool itself perform this "reset" when the object is returned because we should never rely on the fact that the last process to use one of the objects will do so. This is just good practice and provides guarantees on the state of the object.

  

Structure

Fundamentally, an Object pool is merely a container which contains some amount of objects. So, when an object is taken from the pool, it is not available in the pool until it is put back. Objects in the pool have a life-cycle:

  • Creation
  • Validation
  • Destroy

object pool structure

The basic object pool design pattern consists of three basic objects that accomplish all work:

  • Client - This is the class that uses an object of the Reusable Object type.
  • Reusable Object - The PooledObject class is the type that is expensive or slow to instantiate, or that has limited availability, so is to be held in the object pool.
  • Object Pool - The Pool class is the most important class in the object pool design pattern. The Object Pool maintains a list of available objects and a collection of objects that have already been requested from the pool.

In general, it is desirable to keep all Reusable objects that are not currently in use in the same object pool so that they can be managed by a single set of rules. In order to achieve this, the Object Pool class is generally designed to be a singleton class. Its constructor(s) are private, which forces other classes to call the Object Pool's acquireReusable() method to get an instance of the Reusable Object class.

A Client calls an Object Pool's acquireReusable() method when it needs a Reusable object. The Object Pool needs to manage the collection of Reusable Objects and keep track of what has been given out and what is still available. If there are any Reusable objects in the pool when the acquireReusable() method is called, it removes a Reusable object from the pool and returns it to the requester. If the pool is empty, then the acquireReusable() method creates a Reusable object if it can. If the acquireReusable() method cannot create a new Reusable object, then it waits until a Reusable object is returned to the collection.

Client objects pass a Reusable object to a Object Pool's releaseReusable() method when they are finished with the object. The releaseReusable() method returns a Reusable object to the pool of Reusable objects that are not in use; but, only after ensuring that the object has been reset to common starting state.

In many applications of the Object Pool pattern, there are reasons for limiting the total number of Reusable objects that may exist. In such cases, the Object Pool object that creates Reusable objects is responsible for not creating more than a specified maximum number of Reusable objects. If Object Pool objects are responsible for limiting the number of objects they will create, then the Object Pool class will have a method for specifying the maximum number of objects to be created. That method is not indicated in the above diagram.

  

Practical Example

As stated in the STRUCTURE discussion above, the Object is a common approach to returning and managing expensive, time consuming, or limited resources for use in an application. Our example is going to be pretty basic to cover the typical scenarios in where you will find this pattern useful. Here, we will create and manage a pool of expensive to create resources.


object pool example structure

From a real world perspective, there a a number of resources that utilize the object pool pattern: database connections, threads, and things like limiting remote API calls.

  

Code Samples

Below, you will find examples of the Object Pool Pattern implemented in four different commonly used languages. Each one of the examples implements the exact same scenario as described in the PRACTICAL EXAMPLE section above.

Each sample will use the object pool pattern to create and return an expensive object.


C# Object Pool Code Sample

In this C# example, we take advantage of a number of features of the .NET platform that make this extremely simple to implement. The version provided here is highly performant and lazy-loads the items when given a first time use. Here we use the ConcurrentBag as our storage mechanism, although many other types could have been used as weel. In this sample, we chose the ConcurrentBag to address concerns around threading and they are handled in a solid manner in this class.

It is possible to extend this sample to also include items such as items that expire after a given period of time or the use of complex validations for objects that are getting returned. For example, if we were returning connection objects, we might want to ensure their state before handing them out. There would be reason to hand out disconnected cnnection objects in that scenario.


Java Object Pool Code Sample

In this Java example, we are taking advantage of HashTable internally to store instances of the pooled items. It is fairly efficient and provides for quick retrieval of items. Alternately, we could have chosen queues or some other storage class without ill effects.

Unlike the C# example above, we are managing the collection of both the "acquired" and "available" items. This could be done, as it was in the other sample by only tracking the available items. In this sample, I wanted to show how that could be done as it might be valuable if you needed to expire or otherwise do something with loaned out objects.


Typescript Object Pool Code Sample

In this TypeScript example, it is again about as basic as it can get. Note, again as with the other samples, it is the responsibility of the Object Pool to reset the object back to a known clean state that is ready for reuse. You should never rely on the consumers doing this.


JavaScript Object Pool Code Sample

In this JavaScript example, the Object Pool is implemented very simply using an Array. While this choice is not exactly the most performant method of storing the objects, it is simple and still very quick in comparision to creating the objects from scratch each time.

Here, unlike the C# and Java examples, we have implemented a maximum size on the pool. Again, as stated before, this is useful in scenarios where we want to limit the maximum number of managed objects.


  

Considerations

  1. Validate that you have a need to use an object pooling:
    • You must create objects that are expensive to create
    • The frequency of creating further objects is also high.
    • The number of objects in use is small.
  2. Create Object Pool class with private array of Reusable Objects inside
  3. Create acquire and release methods in Object Pool class
  4. Make sure that your Object Pool is Singleton
  

Additional Notes

  • The Factory Method, Abstract Factory, and Builder patterns can be used to encapsulate the creation logic for objects. However, it does not manage them after their creation, the object pool pattern keeps track of the objects it creates.
  • Object Pools are usually implemented as Singletons.
  • Although optional, many Object Pool implementations have the ability to control the minimum and maximum number of items to manage.