Object Pool is a software Creational Design Pattern that is utilized when instantiating a class is expensive in terms of time, computing resources, or both. Essentially, an Object Pool, also known as a Resource Pool, is a container that holds a limited number of objects for a short period of time. It provides a pool of reusable objects. When a new object is needed, it is requested from the pool.
How does the Object Pool pattern work?
A software component (client) with access to an Object Pool can avoid creating new objects by simply asking the pool for one that has already been instantiated. The Client will perform operations on the pool object and, when done, it returns the object to the pool (manually or automatically) rather than destroying it. A pool will create new objects if needed without exceeding a predefined (hardcoded or configurable) limit. For performance reasons, some implementations will create more than one new object at a time, so that a further pool request will be served immediately, without waiting for an object creation if none is available. Additionally, a pool implementation can clean up unused objects according to a time-based policy.
It should be obvious by now that we’ll have only one instance of an Object Pool to which the clients will address their requests.
Implementation involves the following objects:
- Resource – the object which will be shared by several clients for a limited amount of time.
- Client – uses an instance of type Resource.
- ResourcePool – manage the Resource objects for use by Clients, creating and managing a pool of objects.
When a Client asks for a Resource object, the pool performs the following actions:
- Search for an available Resource object and if it was found it will be returned to the Client.
- If no Resource object was found then it tries to create a new one. If this action succeeds the new Resource object will be returned to the Client.
- If the pool was unable to create a new Resource, the pool will wait until a reusable object will be released.
The Client is responsible for requesting and releasing the Resource object to the pool. If this action is not performed, the Resource object will be lost and considered unavailable by the ResourcePool.
The Clients are not aware that they are sharing the Resource object. From the Client‘s point of view, they are the owners of a new object, which comes from the ResourcePool in the same way that it comes from a Factory or another creational design pattern. The only difference is that the Client should mark the Resource object as available after it finishes using it. It’s not about releasing the objects; for example, if we work with databases when a connection is closed, it’s not necessarily destroyed; it means that it can be reused by another client.
An example of Object Pool Creational Design Pattern implementation
For a sample of how this Design Pattern can be put into practice, we are going to use our old friend, the furniture shop application introduced in the post related to Abstract Factory.
Let’s suppose that the Clients of the Furniture Shop can opt-in for delivery and assembling services provided by specialized Service Teams. After a Client has paid for the products, if a Service Team is available, it will manage to load the furniture parts, deliver them to the indicated address, and assemble the furniture. If no Service Team is available or the furniture is not ready yet, the Client will have to wait. After finishing the job, the Service Team will return to the Furniture Shop and be available for another job. The Furniture Shop can decide to hire more people for the Service Teams if the number of orders is high or to reduce their number on the contrary.
In this case, the Resource is the Service Team, and the Furniture Shop is the ResourcePool.
The Object Pool UML diagram for a C# code sample
As shown on the diagram, there are some costly activities that the Service Team should complete before beginning any job that will increase the overall waiting time for a Client. If the Service Team is already prepared, they will be able to serve the Client‘s request much faster.
Advantages of the Object Pool Design Pattern
- Object pooling can offer a significant performance boost when the creation of a class instance is expensive and the rate of instantiation and destruction is high. In these circumstances, objects can be reused frequently, and each reuse saves a significant amount of time. Since memory and possibly other resources, like network sockets, are needed for object pooling, it is preferable that the number of instances in use at any one time is low.
- The pooled object can be obtained in a predictable amount of time, but the creation of new objects, particularly when done over a network, can take a variable time. The advantages are most noticeable for objects that are time-consuming, such as database connections, socket connections, threads, and large graphic objects like fonts or bitmaps.
- In other cases, simple object pooling (which holds no external resources but only occupies memory) may be inefficient and degrade performance. In the case of simple memory pooling, the slab allocation memory management technique is better suited because the only goal is to reduce fragmentation and thus reduce the cost of memory allocation and deallocation.
Disadvantages of the Object Pool Design Pattern
- We must be careful to ensure that the state of the objects returned to the pool is reset for the next use of the object; otherwise, the object may be in an unexpected state for the client, causing it to fail. The pool, not the clients, is in charge of resetting the objects.
- The presence of a stale state is not always an issue; it becomes a problem when the presence of a stale state causes the object to behave abnormally. For example, if the “successfully authenticated” flag is not reset before an object is passed out, it will indicate that a user is correctly authenticated (possibly as someone else) when they have not yet attempted to authenticate. It will, however, function normally if you fail to reset some debugging-only value, such as the identity of the last authentication server used.
- Inadequate object resetting may also result in an information leak. If confidential data (for example, a user’s credit card numbers) is not cleared before an object is passed to a new client, a malicious or buggy client may disclose the data to an unauthorized party.
- If the pool is used by multiple threads, it may require the ability to prevent parallel threads from grabbing and trying to reuse the same object. This is unnecessary if the pooled objects are immutable or otherwise thread-safe.
When to use Object Pooling?
A clue for the cases when the Object Pool design pattern should be used is the need for several clients to access the same stateless resource.
The Object Pool Design Pattern is a creational pattern that provides a pool of pre-initialized objects that can be reused rather than creating and destroying them on demand. This can improve performance and reduce the overhead of creating and destroying objects. When an object is requested, it is obtained from the pool, and when it is no longer needed, it is returned to the pool for reuse. The Object Pool pattern is useful when creating and destroying objects is expensive, and the number of instances needed can vary at runtime. For a sample implementation using C# 11, you can find the source code on GitHub.