If you need to reduce the work of the garbage collector in Android, like in games development for example, all you can do is reduce the amount of objects you create and recycle those you’ve already created. One of the ways to do this is the implementation of the Object Pool design pattern.
An Object Pool could be implemented in many different ways depending on the needed features. What I’m going to show here is an implementation that respects the following requirements:
- during its execution, the Object Pool doesn’t allocate new objects other than those contained in the pool itself (we prefer plain arrays instead of Java collections);
- the Object Pool must be efficient in terms of execution speed;
- the Object Pool is responsible for initializing and finalizing the objects it contains (the objects must be ready to use when retrieved from the pool and they must free any unneeded resource when they are put back in the pool);
- if there’s no more room for new objects in the pool, then new objects must be created anyway if requested, but they’ll not be stored in the pool when freed;
- the Object Pool must be able to handle every type of Object (we only ask the objects to implement an interface to make them ready for the pool);
- sharing the pool between multiple threads doesn’t have to be a problem.
And now, straight to the source code. We start with the definition of the PoolObject interface:
/**
* Interface that has to be implemented by an object that can be
* stored in an object pool through the ObjectPool class.
*/
public interface PoolObject
{
/**
* Initialization method. Called when an object is retrieved
* from the object pool or has just been created.
*/
public void initializePoolObject();
/**
* Finalization method. Called when an object is stored in
* the object pool to mark it as free.
*/
public void finalizePoolObject();
}
This is the interface that an object must implement to let the pool perform two operations: the initialization and the finalization. We use an interface so we can easily extend every other class and make the pool able to handle different objects.
The Object Pool creates the needed objects through a factory class that implements the PoolObjectFactory interface:
/**
* Interface that has to be implemented by every class that allows
* the creation of objectes for an object pool through the
* ObjectPool class.
*/
public interface PoolObjectFactory
{
/**
* Creates a new object for the object pool.
*
* @return new object instance for the object pool
*/
public PoolObject createPoolObject();
}
The factory class must decide how to create a new PoolObject instance whenever the pool needs it.
All we need to see now is the ObjectPool class, so let’s take a look at it:
/**
* Object pool implementation.
*/
public class ObjectPool
{
protected final int MAX_FREE_OBJECT_INDEX;
protected PoolObjectFactory factory;
protected PoolObject[] freeObjects;
protected int freeObjectIndex = -1;
/**
* Constructor.
*
* @param factory the object pool factory instance
* @param maxSize the maximun number of instances stored in the pool
*/
public ObjectPool(PoolObjectFactory factory, int maxSize)
{
this.factory = factory;
this.freeObjects = new PoolObject[maxSize];
MAX_FREE_OBJECT_INDEX = maxSize - 1;
}
/**
* Creates a new object or returns a free object from the pool.
*
* @return a PoolObject instance already initialized
*/
public synchronized PoolObject newObject()
{
PoolObject obj = null;
if (freeObjectIndex == -1)
{
// There are no free objects so I just
// create a new object that is not in the pool.
obj = factory.createPoolObject();
}
else
{
// Get an object from the pool
obj = freeObjects[freeObjectIndex];
freeObjectIndex--;
}
// Initialize the object
obj.initializePoolObject();
return obj;
}
/**
* Stores an object instance in the pool to make it available for a subsequent
* call to newObject() (the object is considered free).
*
* @param obj the object to store in the pool and that will be finalized
*/
public synchronized void freeObject(PoolObject obj)
{
if (obj != null)
{
// Finalize the object
obj.finalizePoolObject();
// I can put an object in the pool only if there is still room for it
if (freeObjectIndex < MAX_FREE_OBJECT_INDEX)
{
freeObjectIndex++;
// Put the object in the pool
freeObjects[freeObjectIndex] = obj;
}
}
}
}
The structure of this class is very simple. There are only three methods, the constructor and two other methods to create and free the object instances.
The constructor accepts two parameters, the factory instance and the maximum number of objects that can be stored in the pool.
The newObject method retrieves an object from the pool and returns it to the caller after initializing it. If there are free objects in the pool, then one of those is returned, otherwise a new one is created through the factory. In this way we put a limit on the maximum number of instances in the pool, but only the needed amount is actually created.
The freeObject method puts an object instance back in the pool making it available for subsequent calls to newObject. Before storing the object in the free objects array, its finalization method is called to let it free any unneeded resource if necessary. If there’s no room in the pool for the object, then only its finalization method is called.
Both the newObject and the freeObject methods are synchronized so the interaction between the pool and different threads is managed correctly.
We have all we need, so let’s take a look at an example to see how our new tool can be used and what is its benefit. Let’s say that we need to work with Point instances for a graphic application. We need to have many points, but we want to avoid to keep on creating them and try to reuse the instances if possible. We need to define a PoolObject first: Read more