BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Design Patterns
.NET 3.5+

A Generic Object Pool

The object pool design pattern can improve performance by reusing objects that are expensive to instantiate, rather than creating new instances. This article describes a generic implementation of the object pool pattern.

Adding Clean-Up Operations

The lack of a clean-up operation could cause serious problems. Reusing objects and not resetting their properties correctly could easily cause corruption.

We can see the problem with a simple modification to the test code. Replace the contents of the Main method as follows and re-run the program. Note that the third object remembers the Name property from its prior use. This can be seen in the third line of the output.

var pool = new Pool<PooledObject>();

var obj1 = pool.Get();
obj1.Name = "First";
Show(obj1);

var obj2 = pool.Get();
obj2.Name = "Second";
Show(obj2);

pool.Release(obj1);

var obj3 = pool.Get();
Show(obj3);

obj3.Name = "Third";
Show(obj3);

/* OUTPUT

1 - First
2 - Second
1 - First
1 - Third

*/

As the clean-up code will vary according to the type being pooled, we need some way to provide the functionality to the Pool class. A simple way is to inject a delegate into the pool. The delegate needs to take a parameter of the pooled type so that the object being released can be identified. We'll use an Action delegate for this purpose, which has the advantage that we will be able to supply the clean-up code as a lambda expression.

We need a field in which to store the Action delegate. To create it, add the following code to the Pool class, outside of any method or property:

Action<T> _cleanUp;

We'll use constructor injection to provide the delegate. Add the following constructor, which receives the delegate, checks that it is valid and stores it in the field.

public Pool(Action<T> cleanUp)
{
    if (cleanUp == null) throw new ArgumentNullException("cleanUp");

    _cleanUp = cleanUp;
}

Finally, we need to call the delegate from the CleanUp method.

private void CleanUp(T obj)
{
    _cleanUp(obj);
}

To test the new functionality, modify the Main method's contents as shown below. The updated code includes a lambda expression to define the clean-up process. The lambda simply resets the Name to null. The PermanantId is unchanged so that we can see that pooling is still working correctly.

When you run the program you will see that the name is removed when objects are released to the pool. The third output line shows that the name was cleared correctly.

var pool = new Pool<PooledObject>(p => { p.Name = null; });

var obj1 = pool.Get();
obj1.Name = "First";
Show(obj1);

var obj2 = pool.Get();
obj2.Name = "Second";
Show(obj2);

pool.Release(obj1);

var obj3 = pool.Get();
Show(obj3);

obj3.Name = "Third";
Show(obj3);

/* OUTPUT

1 - First
2 - Second
1 -
1 - Third

*/
23 July 2013