The Object Pool

The Object Pool

Dear reader, welcome back to this series of short-and-sweet articles on software design patterns.

In this article we’re going to study the “Object Pool” pattern, which can be seen as a memory allocation strategy adopted by applications that require large amounts objects during their life.

What is it?

Object Pool is a pattern based on custom-container theory. An object pool is a container that helps reducing the amount of memory allocated by systems that may require a large number of objects of the same type during runtime.

The container acts as manager for objects that are pre-allocated in the beginning of the application and will exist through its entire lifetime, thus reducing the amount of calls to “new”, “delete” or the overall garbage collection work.

There is no standard way to design a pool, as long as the implementation respects the concept described above. This article will discuss two different versions; however, students are encouraged to experiment based on their own use-cases.

 How does it work?

Often times a pool will wrap around an existing native container such as arrays, queues, dictionaries, and others, in order to be able to collect objects. Therefore, the class itself should provide means for the application to insert, remove, search and get/take stored items.

No alt text provided for this image

The diagram above outlines the core principle of this pattern, in which instead of creating and disposing objects during runtime, the application will take an existing element from the pool, use it, then put it back on the pool. Notice how this changes the behavior of the application, moving from continuously consuming objects (allocating/freeing memory) to recycling them (reusing memory).

As an example, a particle system could benefit from this strategy. By employing object pooling, the developer can create all particles at once and use a lifetime to control when particles are pulled or returned to the container, therefore reducing the impact on the memory.

How does it look like in code?

This tutorial uses C# + .NET Core 3.1. However, any other object-oriented programming language would work just fine since design patterns are, usually, language-agnostic.

The basic functionality of our pools is enforced by an IObjectPool<T> interface.

public interface IObjectPool<T> : IDisposable where T : IComponent
{   
    bool Add(T value);   
    bool Remove(T value);
    T FindObjectByID(uint id);
    T FindObjectByName(string name);
    int GetCount();
    int GetCount<T1>() where T1 : IComponent;
}
 

Where T refers to any object that inherit from an IComponent interface.

public interface IComponent
{
   IComponent Owner { get; set; }
   string Name { get; set; }
   uint ID { get; set; }
   bool IsEnabled { get; set; }
    
}

There are two pools implemented in this project, each with a different strategy:

ObjectPool1:

  • A pool that does not take ownership of its elements and therefore does not alter any of their properties.
  • The application can pick elements forwards or backwards in the underlying container through the TryGetNext(…) and TryGetPrevious(…) methods.
  • Elements are always preserved in the container even when in use by the application.
No alt text provided for this image
public class ObjectPool1<T> : IObjectPool<T> where T : IComponent
{        
    private readonly List<T> pool = null;       
    private int indexOfLastObjectUsed = -1;
    private bool isMovingForward = true;

    public ObjectPool1() {...}

    public bool Add(T value) {...}
    public bool Remove(T value){...}
    public bool TryGetNext(out T value){...}
    public bool TryGetPrevious(out T value){...}
    public T FindObjectByID(uint id){...}
    public T FindObjectByName(string name){...}
    public int GetCount() => pool.Count;{...}
    public int GetCount<T1>() where T1 : IComponent{...}
    public void Dispose(){...}
}

This implementation saves the index of the last object used by the application (indexOfLastObjectUsed) and increments/decrements its value every time an item is picked. Moreover, it also stores if the last TryGet call was moving forwards or backwards in the container.

ObjectPool2:

  • A pool that takes ownership of its elements and will change the value of their IsEnabled property. Once an element is taken, it becomes enabled (or active); when the element is reintroduced, it becomes disabled.
  • The application can pick elements through the TryTakeObject(...) method. After using the element, the application must return it with the Add(...) method.
  • Elements are not always preserved in the container during runtime.
No alt text provided for this image
public class ObjectPool2<T> : IObjectPool<T> where T : IComponent
{
    private readonly List<T> pool = null;
        
    public ObjectPool2() {...}

    public bool Add(T value) {...}
    public bool Remove(T value) {...}
    public bool TryTakeObject(uint id, out T value) {...}
    public bool TryTakeObject(string name, out T value) {...}
    public T FindObjectByID(uint id) {...}
    public T FindObjectByName(string name) {...}
    public int GetCount() => pool.Count; {...}
    public int GetCount<T1>() where T1 : IComponent {...}

    public void Dispose(){...}
}

This implementation requires the application to know the identification of the element to be taken from the pool. If the linear search is successful, then the element is removed from the List<T> and given to the application.

Testing

The 'main' of our console application tests both approaches by inserting the same number of TestComponents in both pools. Notice how the element count never changes for ObjectPool1, but decreases over the iterations for ObjectPool2.

Head over to the GitHub page at https://github.com/Fe-Bell/DesignPatternsTutorials to download all commented samples from this series. This article refers to the ObjectPool solution.

There are many ways to develop this pattern. How many different strategies can you imagine for the ObjectPool? What is your use-case?

As always, let us know in the comments section!


This series is part of The Kung Fu Of Code initiative!

To view or add a comment, sign in

More articles by Felipe Bellini

  • The Future of Programming Languages

    Not long ago I was having a conversation with a colleague of mine and the topic of discussion was the way forward in…

  • Singleton Pattern

    What is it? Singleton is one of the earliest and most known design patterns in Object Oriented Programming. This simple…

    2 Comments
  • The Entity-Component System

    Dear reader, welcome to this series of quick-and-sweet articles on software design patterns. Having worked for so many…

    2 Comments

Explore content categories