Object Pooling with Managed Code


Summary

With the advent of the .NET platform, writingcode that pools objects and threads has become a simple task. By usingthe Threading and Collections namespaces, you can create robust objectpooling applications. This could also be done by implementing COM+interop interfaces into your code. If you don't have any reservationsabout the additional overhead of marshalling as well as the tightcoupling of your code to COM+, then use COM+ interop. On the otherhand, if you are looking for advanced control and better overallperformance, then you can write your own object pools.

Download objectpooling_code.zip

Writing your own object pools has the following benefits:

� Custom performance counters – Customperformance counters can be easily implemented into your code. AlthoughCOM+ offers several performance counters, I have often found the needto have additional performance counters related to how my objects arebeing pooled.
� Custom tracing and event logging – Objects can use theTrace.Write(If) methods to log events and errors. This leaves where andhow an event is logged up to the hosting application. This approachalso allows for centralized handling of events and errors.
� Custom messaging – You can create customized messaging schemesthat replace LCE (Loosely Coupled Events) thus improving the overallperformance of your application.
� No interop marshalling – Because all your object pooling codeis written in the managed environment, your code will run marginallyfaster (given that you write your code efficiently).The caveats to creating your own object pools are:
� More coding. Using COM+ is as simple as adding an attribute.
� Code is more complex, thus requiring more programmers with advanced skills. In my projects, I have used both COM+ and custom object pooling depending on the timeframes and requirements of the projects.

Defining the Namespaces

The namespaces used for the project are as follows:

namespace Sample.ObjectPooling{
using System;
using System.Collections;
using System.Reflection;
using System.Threading;

Creating the Object Context Class

The object context class will be responsiblefor managing the lifetime of the pooled object. This object could alsocontain addition information about the object.

public class ObjectContext{
internal Stack m_oStack;
private int m_iTimeout;
public bool TimedOut = false;
public object Object;
public ObjectContext(Stack Stack, int Timeout){
this.m_iTimeout = Timeout;
this.m_oStack = Stack;
}
private Timer IdleTimer = null;
private void IdleTimeoutCallback(object State){this.StopIdleTimer(); this.TimedOut = true;}
public bool TimedOut = false;
internal void StopIdleTimer(){this.IdleTimer.Dispose();}
public void Dispose(){
this.StopIdleTimer();
this.TimedOut = true;
this.m_oStack = null;
this.Object = null;
}
public void Pool(){
this.IdleTimer = new Timer(new TimerCallback(this.IdleTimeoutCallback),null,m_iTimeout,0);
this.m_oStack.Push(this);
}
}

This class contains a constructor into whichthe parent passes a reference to its containing stack (the object pool)and the idle timeout period (in milliseconds). When an object is pulledfrom the stack, the StopIdleTimer method is called by the parent toensure that the object doesn't timeout inaccurately. When the user ofthe object is done, it calls on the object context's Pool method whichadds the object back to the pool (i.e. pushes an object reference ontothe stack).

If at any point, the internal idle-timeouttimer elapses, the object context disposes of all external referencesand sets its TimedOut field to true. This field is used by the parentclass to know which objects can be cleaned up (i.e. removed from thestack).

Creating the Object Pooling Class

The next step is to create the ObjectPoolingclass. This class uses a Collections.Stack object along with theObjectContext class to create and manage its object pool.

public class ObjectPool{
private Type m_oType;
private int m_iTimeout = 60000;
internal Stack m_oPool = new Stack();
public ObjectPool(System.Type Type){
this.m_oType = Type;
}
public ObjectPool(System.Type Type, int Timeout){
this.m_oType = Type;
this.m_iTimeout = Timeout;
}
public Type Type{get{return m_oType;}}
public ObjectContext GetObjectContext(){return this.GetObjectContext(null);}
public ObjectContext GetObjectContext(object[] Args){
ObjectContext oObject = null;
while(m_oPool.Count!=0){
oObject = (ObjectContext)m_oPool.Pop();
if(!(oObject.TimedOut)){
oObject.StopIdleTimer();
break;
}
else{oObject=null;}
}
if(oObject==null){
oObject = new ObjectContext(m_oPool, m_iTimeout);
oObject.Object = Activator.CreateInstance(m_oType, Args);
}
return oObject;
}
public void Dispose(){
while(m_oPool.Count!=0){
ObjectContext oItem = (ObjectContext)m_oPool.Pop();
oItem.Dispose();
}
}
}
}

When creating the object pool, the type ofobject stored in the pool along with the idle timeout is specified. Themost significant method of this class is GetObjectContext. This methodlooks for an existing object (and its context) in the pool. If noobject can be found in the pool, a new object (and context) is created.If the object was obtained from the stack, the StopIdleTimer method iscalled on the object's context to ensure that it doesn't time-out.

The Dispose method is used to clean-up anyobject that are in the queue. This method should always be called whenthe object pool is no longer needed (normally at application shutdown).

Using the Object Pool

The following code is an example of using theobject pool classes above to create one or more worker objects. Eachworker object pops up a message box that contains its hash code. Bypressing the enter key in the console at different intervals, you cansee how some objects will timeout and others will be reused. Thedefault timeout used for this sample is 1 minute.

namespace WindowsApplication2{
using System;
using System.WinForms;
using Sample.ObjectPooling;
using System.Threading;
public class Test{
private static void Main(){
ObjectPool oPool = new ObjectPool(typeof(WindowsApplication2.Worker));
while(Console.ReadLine() != "x"){
ObjectContext oContext = oPool.GetObjectContext();
ThreadPool.QueueUserWorkItem(new WaitCallback(new Test().ThreadProc), oContext);
}
oPool.Dispose();
}
public void ThreadProc(object State){
ObjectContext oContext = (ObjectContext)State;
((Worker)oContext.Object).ShowHashCode();
oContext.Pool();
}
}
public class Worker{
public void ShowHashCode(){
MessageBox.Show(this.GetHashCod
e().ToString());
}
}
}

Conclusion

As you can see, creating an object pool hasbecome a trivial task using the .NET framework. One improvement on theabove code would be to add performance counters along with remotingcapabilities to your object pool.

About The Author

Scott Sherer is a Systems Architect based outof Phoenix, Arizona. He started programming at the age of 10 and hasloved programming with a passion ever since. His experiences haveincluded Document Imaging, Building Automation Systems, and Banking. Hehas been using C# and the .NET framework since December, 2000, and iscurrently on contract with the City of Phoenix where he is assisting inthe conversion of existing software to the new .NET platform. You canreach him at scotts@dakinisoft.com.

Most Commented Articles :

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

No comments yet... Be the first to leave a reply!