Understanding Object Pooling in Microsoft .NET
 
Published: 29 Jan 2007
Abstract
In this article Joydip discusses what an Object Pool is and how we can implement one in .NET with the help of code examples in C#.
by Joydip Kanjilal
Feedback
Average Rating: 
Views (Total / Last 10 Days): 46730/ 73

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

using System;
using System.ComponentModel; 
using System.Collections; 
using System.Threading; 
 
namespace ObjectPooling
{
      /// <summary>
      /// A class to manage objects in a pool. 
///The class is sealed to prevent further inheritence
      /// and is based on the Singleton Design.
      /// </summary>
      public sealed class PoolManager
      {
            private Queue poolQueue = new Queue();
            private Hashtable objPool = new Hashtable();
            private static readonly object objLock = new object();
            private const int POOL_SIZE = 10;
            private int objCount = 0;
            private static PoolManager poolInstance = null;
 
            /// <summary>
            /// Private constructor to prevent instantiation
            /// </summary>
            private PoolManager()
            {
 
            }
 
            /// <summary>
            /// Static constructor that gets 
///called only once during the application's lifetime.
            /// </summary>
            static PoolManager()
            {
                  poolInstance = new PoolManager();
            }
 
            /// <summary>
            /// Static property to retrieve the instance of the Pool Manager
            /// </summary>
 
            public static PoolManager Instance 
            {
                  get
                  {
                        if(poolInstance != null) 
                        {
                              return poolInstance;
                        }
 
                        return null;
                  }
            }
 
            /// <summary>
            /// Creates objects and adds them in the pool
            /// </summary>
            /// <param name="obj">The object type</param>
            public void CreateObjects(object obj)
            {
                  object _obj = obj;
                  objCount = 0;
                  poolQueue.Clear();
                  objPool.Clear();
 
                  for(int objCtr = 0; objCtr < POOL_SIZE ; objCtr ++)
                  {
                        _obj = new object();
 
                        lock(objLock)
                        {
                              objPool.Add(_obj.GetHashCode(),_obj);
                              poolQueue.Enqueue(_obj);
                              objCount ++;                              
                        }
                  }
            }
 
            /// <summary>
            /// Adds an object to the pool
            /// </summary>
            /// <param name="obj">Object to be added</param>
            /// <returns>True if success, false otherwise</returns>
            public bool AddObject(object obj)
            {
                  if(objCount == POOL_SIZE)
                        return false;
 
                  lock(objLock)
                  {
                        objPool.Add(obj.GetHashCode(),obj);
                        poolQueue.Enqueue(obj);
                        objCount ++;
                  }
 
                  return true;
            }
 
            /// <summary>
            /// Releases an object from the pool at the end of the queue
            /// </summary>
            /// <returns>The object if success, null otherwise</returns>
            
            public object ReleaseObject()
            {
                  if(objCount == 0)
                        return null;
 
                  lock(objLock)
                  {
                        objPool.Remove(poolQueue.Dequeue().GetHashCode());
                        objCount --;
                        if(poolQueue.Count > 0)
                              return poolQueue.Dequeue();                     
                  }
 
                  return null;
            }
 
            /// <summary>
            /// Releases an object from the pool
            /// </summary>
            /// <param name="obj">Object to remove from the pool</param>
            /// <returns>The object if success, null otherwise</returns>
            public object ReleaseObject(object obj)
            {
                  if(objCount == 0)
                        return null;
 
                  lock(objLock)
                  {
                        objPool.Remove(obj.GetHashCode());
                        objCount --;
                        RePopulate();
                        return obj;
                  }
            }
 
            /// <summary>
            /// Method that repopulates the 
///Queue after an object has been removed from the pool.
            /// This is done to make the queue 
///objects in sync with the objects in the hash table.
            /// </summary>
            private void RePopulate()
            {
                  if(poolQueue.Count > 0)
                        poolQueue.Clear();
 
                  foreach (int key in objPool.Keys)
                  {
                        poolQueue.Enqueue(objPool[key]);
                  }
            }
 
            /// <summary>
            /// Property that represents the current no of objects in the pool
            /// </summary>
            public int CurrentObjectsInPool
            {
                  get
                  {
                        return objCount;
                  }
            }
 
            /// <summary>
            /// Property that represents the maximum no of objects in the pool
            /// </summary>
            public int MaxObjectsInPool
            {
                  get
                  {
                        return POOL_SIZE;
                  }
            }
      }
}

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

PoolManager poolManager = PoolManager.Instance;
object obj1 = new object();
object obj2 = new object();
object obj3 = new object();
poolManager.AddObject(obj1);
poolManager.AddObject(obj2);
 
MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());
object obj = poolManager.ReleaseObject();
MessageBox.Show(poolManager.CurrentObjectsInPool.ToString());
if(obj.GetHashCode() == obj1.GetHashCode())
      MessageBox.Show("Object 1 has been released from the pool");
else if(obj.GetHashCode() == obj2.GetHashCode())
      MessageBox.Show("Object 2 has been released from the pool");

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. I leave it to the readers to make the necessary changes to the Pool Manager class to suit their needs.

References

Conclusion

Object Pooling is a mechanism that facilitates re-using of the existing objects in a pool (a container of live objects) rather than creating or re-creating them anew each time they are needed. This article has discussed the basic concepts of Object Pooling and how we can implement the same in .NET using C# as the language of choice. Stay tuned for more such articles on Object Pooling where I will discuss more on real-life implementation issues related to this concept. I hope readers will find this article helpful in giving a basic understanding of Object Pooling and how it works apart from implementing a simple Object Pool in C#.



User Comments

No comments posted yet.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-23 1:52:21 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search