Monday, March 17, 2008

  1. Introduction
    Object Pooling is nothing new. It is a concept that implies that we can store a pool of objects in memory to be reused later and, hence, reduce the load of object creation to a great extent. An Object Pool, also known as a Resource Pool, is a list/set of ready to be used reusable objects that reduce the overhead of creating each object from the scratch whenever a request for an object creation comes in. This is somewhat similar to the functioning of a Connection Pool, but with some distinct differences. This article throws light on this concept (Object Pooling) and discusses how we can implement a simple generic Object Pool in .NET.

    What is an Object Pool?
    An Object Pool may be defined as a container of objects that are ready for use. Lists of ready-to-be-used objects are contained in this pool. Whenever a new request for an object creation comes in, the request is served by allocating an object from the pool. Therefore, it reduces the overhead of creating and re-creating objects each time an object creation is required. "An object pool is an object that holds a list of other objects, ready to make them available for use (to yet another object, probably). It does the management work involved, like keeping track of which objects are currently in use, how many objects the pool holds, whether this number should be increased."

    Why is an Object Pool required?
    The biggest advantage of using Object Pooling is that it minimizes the consumption of memory and the system's resources by recycling and re-using objects as and when it is needed and serving the request for new objects from the pool of ready-to-be-used objects. The objects that the application is done with (the objects are no longer needed) are sent back to the pool rather than destroying them from the memory. According to MSDN, "Once an application is up and running, memory utilization is affected by the number and size of objects the system requires. Object pooling reduces the number of allocations, and therefore the number of garbage collections, required by an application. Pooling is quite simple: an object is reused instead of allowing it to be reclaimed by the garbage collector. Objects are stored in some type of list or array called the pool, and handed out to the client on request. This is especially useful when an instance of an object is repeatedly used, or if the object has an expensive initialization aspect to its construction such that it's better to reuse an existing instance than to dispose of an existing one and to create a completely new one from scratch."

    How does an Object Pool work?
    When an object is requested, it is served from the pool. When the object is disposed, it is placed back into the pool to await the next request that might come in at a later point in time. The pool initially consists of a number of objects. When a request for creation of an object comes in, the request is server from the pool of objects and the number of the available objects in the pool decreases by one. This process continues until the pool runs out of objects. The pool remains in memory as long as there is at least one object in the pool. The pool facilitates reusability and eliminates the overhead involved in creation of objects whenever they are requested. The following section discusses how an Object Pool (though somewhat similar to a Connection Pool) differs from a Connection Pool. You can find my article on Connection Pooling here.

    How does Object Pooling and Connection Pooling differ?
    There are distinct differences between Object pooling and Connection Pooling. Object Pooling is great in the sense that it can optimize access to expensive resources (like file handles or network connections) by pooling them in memory and reusing them as and when they are needed. According to MSDN, "Object pooling lets you control the number of connections you use, as opposed to connection pooling, where you control the maximum number reached."

    Implementing an Object Pool in C#
    We would design an object pool based on some predefined goals/objectives. These are stated as under the following.

    Ease of use and reusable
    Thread Safe
    Type Safe
    Scalable
    Configurable
    These are the basic objectives that the pool should adhere to. With these in mind, we will now implement a simple Object Pool in C# and use this pool for creation, usage and destruction of objects.

    The Pool Manager Class

    The following code example illustrates how an object pool can be created. I have provided enough comments to enable the reader to understand how the Pool Manager class works. This class is based on the Singleton Pattern, i.e., there can be at any point of time only one instance of this class.

    Listing 1
    1 using System;

    2 using System.ComponentModel;

    3 using System.Collections;

    4 using System.Threading;

    5

    6 namespace ObjectPooling

    7 {

    8 /// <summary>

    9 /// A class to manage objects in a pool.

    10

    11 ///The class is sealed to prevent further inheritence

    12 /// and is based on the Singleton Design.

    13 /// </summary>

    14 public sealed class PoolManager

    15 {

    16 private Queue poolQueue = new Queue();

    17 private Hashtable objPool = new Hashtable();

    18 private static readonly object objLock = new object();

    19 private const int POOL_SIZE = 10;

    20 private int objCount = 0;

    21 private static PoolManager poolInstance = null;

    22

    23 /// <summary>

    24 /// Private constructor to prevent instantiation

    25 /// </summary>

    26 private PoolManager()

    27 {

    28

    29 }

    30

    31 /// <summary>

    32 /// Static constructor that gets

    33 ///called only once during the application's lifetime.

    34

    35 /// </summary>

    36 static PoolManager()

    37 {

    38 poolInstance = new PoolManager();

    39 }

    40

    41 /// <summary>

    42 /// Static property to retrieve the instance of the Pool Manager

    43

    44 /// </summary>

    45

    46 public static PoolManager Instance

    47 {

    48 get

    49 {

    50 if(poolInstance != null)

    51 {

    52 return poolInstance;

    53 }

    54

    55 return null;

    56 }

    57 }

    58

    59 /// <summary>

    60

    61 /// Creates objects and adds them in the pool

    62 /// </summary>

    63 /// <param name="obj">The object type</param>

    64 public void CreateObjects(object obj)

    65 {

    66 object _obj = obj;

    67 objCount = 0;

    68 poolQueue.Clear();

    69 objPool.Clear();

    70

    71 for (int objCtr = 0; objCtr < _obj =" new" name="obj" objcount ="="" objcount ="=""> 0)

    122 return poolQueue.Dequeue();

    123 }

    124

    125 return null;

    126 }

    127

    128 /// <summary>

    129

    130 /// Releases an object from the pool

    131 /// </summary>

    132 /// <param name="obj">Object to remove from the pool</param>

    133 /// <returns>The object if success, null otherwise</returns>

    134

    135 public object ReleaseObject(object obj)

    136 {

    137 if(objCount == 0)

    138 return null;

    139

    140 lock(objLock)

    141 {

    142 objPool.Remove(obj.GetHashCode());

    143 objCount --;

    144 RePopulate();

    145 return obj;

    146 }

    147 }

    148

    149 /// <summary>

    150

    151 /// Method that repopulates the

    152 ///Queue after an object has been removed from the pool.

    153 /// This is done to make the queue

    154 ///objects in sync with the objects in the hash table.

    155 /// </summary>

    156 private void RePopulate()

    157 {

    158 if(poolQueue.Count > 0)

    159 poolQueue.Clear();

    160

    161 foreach (int key in objPool.Keys)

    162 {

    163 poolQueue.Enqueue(objPool[key]);

    164 }

    165 }

    166

    167 /// <summary>

    168

    169 /// Property that represents the current no of objects in the pool

    170 /// </summary>

    171 public int CurrentObjectsInPool

    172 {

    173 get

    174 {

    175 return objCount;

    176 }

    177 }

    178

    179 /// <summary>

    180

    181 /// Property that represents the maximum no of objects in the pool

    182 /// </summary>

    183 public int MaxObjectsInPool

    184 {

    185 get

    186 {

    187 return POOL_SIZE;

    188 }

    189 }

    190 }

    191 }

    Using the Pool Manager Class

    The following code snippets in Listings 2, 3 and 4 show how we can use the PoolManager created in Listing 1.

    Listing 2
    object obj1 = new object();
    object obj2 = new object();
    PoolManager poolManager = PoolManager.Instance;
    poolManager.AddObject(obj1);
    poolManager.AddObject(obj2);
    MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());
    poolManager.ReleaseObject(obj1);
    MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());

    object obj = null;
    for(;;)
    {
    obj = poolManager.ReleaseObject();
    if(obj != null)
    MessageBox.Show(obj.GetHashCode().ToString());
    else

    {
    MessageBox.Show("No more objects in the pool");
    break;
    }
    }Listing 3
    object obj1 = new object();

    object obj2 = new object();

    PoolManager poolManager = PoolManager.Instance;

    poolManager.AddObject(obj1);

    poolManager.AddObject(obj2);

    MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());

    poolManager.ReleaseObject(obj1);

    MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());



    object obj = null;



    for(;;)

    {

    obj = poolManager.ReleaseObject();

    if(obj != null)

    MessageBox.Show(obj.GetHashCode().ToString());

    else

    {

    MessageBox.Show("No more objects in the pool");

    break;

    }

    }

    Listing 4
    PoolManager poolManager = PoolManager.Instance;

    ArrayList arr = new ArrayList();

    poolManager.CreateObjects(arr);



    object obj = poolManager.ReleaseObject();

    MessageBox.Show("No of objects in Pool is: " +

    poolManager.CurrentObjectsInPool.ToString(),

    "The hash code of the released object is: " +

    obj.GetHashCode().ToString());

    obj = poolManager.ReleaseObject();

    MessageBox.Show("No of objects in Pool is: " +

    poolManager.CurrentObjectsInPool.ToString(),

    "The hash code of the released object is: " +

    obj.GetHashCode().ToString());

    Note how we have used the PoolManager in the code listings above. The CreateObjects method has been used in Listing IV to create a specified number of objects of the ArrayList type and store them in the pool. However, the major drawback of this design is that there would be enough boxing and un-boxing overhead involved on storing and retrieving the objects to and fro from the pool. To eliminate this, I would recommend the usage of Generics. Further, the size of the pool (the maximum number of objects that the pool can contain) is also fixed and is not configurable.

No comments: