What is object pooling in C#?

Object pooling is a design pattern used to track and recycle expensive objects rather than recreating them whenever the application needs them. It consists of a pooling container, which holds reusable instances of objects. These are then doled out as needed and returned to the pool once their immediate purpose is fulfilled.

Benefits of object pooling

Repeated memory allocation in C# is expensiveExpensive processes are CPU intensive, leading to performance issues., especially for large programs. This is because memory is allocated on the heap, which has a slower access and retrieval process than the stack. For memory-intensive applications, creating new objects for every use adversely impacts performance.

In this case, object pooling helps boost the performance of C# applications by keeping reusable instances of objects in a resource pool. This reduces the overhead of initialization, allocation, and disposal of objects.

Uses

The object pooling pattern is helpful in large applications, where object creation and destruction frequency is high. Moreover, if the objects are similar in size and represent a complex resource such as a network connection, using object pools to store and reuse them might be beneficial.

However, object pooling does not come without some downsides. Firstly, the memory size in a heap is fixed for each object. If the objects added to the pool vary in size, there's memory wastage and the risk of a large object overwriting the next one. Secondly, as our objects are not being cleared by a memory manager (or the garbage collector), the onus falls on the developer to clear the memory. Otherwise, unneeded objects may remain dormant for long, leading to potential performance overheads.

How it works

Object pooling consists of the following order of events:

  1. The application requests an object instead of creating one. If the object is available in the pool, it is removed from the pool temporarily.

  2. In case the object is unavailable, the pool creates a new object.

  3. Once used, the object is returned to the pool, and its data is cleared for reuse.

  4. The next time the application requires the same object, the now-empty object is taken from the pool.

The maximum number of objects allowed in a pool is up to the developer. There are several ways to implement a handling strategy in case this maximum allowance is reached:

  • Return null or throw an exception

  • Increase the limit of objects in the pool

  • Wait for an object to be removed from the pool

Example

To demonstrate object pooling, we will create a Student class to show how the same objects can be reused.

Create the object pool

We'll begin by creating a custom objectPool class with the methods getObj() and releaseObj(). In this example, we will use the list collection in C#. However, queues can also be used for this purpose. The code is shown below:

public class objectPool<T> where T : new()
{
// list to hold the objects
private List<T> objectsList = new List<T>();
//counter keeps track of the number of objects in the pool
private int counter = 0;
// max objects allowed in the pool
private int maxObjects = 5;
// returns the number of objects in the pool
public int getCount()
{
return counter ;
}
// method to get object from the pool
public T getObj()
{
// declare item
T objectItem;
// check if pool has any objects
// if yes, remove the first object and return it
// also, decrease the count
if (counter > 0)
{
objectItem = objectsList[0] ;
objectsList.RemoveAt(0) ;
counter--;
return objectItem;
}
// if the pool has no objects, create a new one and return it
else
{
T obj = new T();
return obj;
}
}
// method to return object to the pool
// if counter is less than the max objects allowed, add object to the pool
// also, increment counter
public void releaseObj(T item)
{
if(counter < maxObjects)
{
objectsList.Add(item);
counter++;
}
}
}

Explanation

The following is the explanation of the code for a custom object pool class:

  • Lines 4–8: We declare class variables. objectsList is the pool in which we'll add our object and counter is the number of objects in the pool at a point. maxObjects is the maximum allowable objects in the pool, where the number is up to the programmer.

  • Lines 17–37: The getObject() method first checks if the pool has any available objects. If it does, it removes the object from the pool and returns it. Otherwise, it creates a new object and returns that.

  • Lines 42–49: The releaseObj() method checks if the number of objects in the pool is less than the maximum number of objects allowed. If true, it adds the released object to the pool and increments the counter.

Create a Student class

Now that we've our generic object pool, let's create a simple Student class to see our design in action. This class stores a student's first name and ID, with methods to get and set these variables.

// declaring a student class for demonstration purposes
class Student
{
private string firstName;
private int studentID;
public string getName()
{
return firstName ;
}
public void setName(string name)
{
firstName = name ;
}
public int getID()
{
return studentID ;
}
public void setID(int ID)
{
studentID = ID ;
}
}

Put it all together

With our sample class and object pool ready, let's put it together and see how objects are assigned. The following code demonstrates this:

using System;
using System.Collections.Generic;
using System.Collections;
public class objectPool<T> where T : new()
{
// list to hold the objects
private List<T> objectsList = new List<T>();
//counter keeps track of the number of objects in the pool
private int counter = 0;
// max objects allowed in the pool
private int maxObjects = 5;
// returns the number of objects in the pool
public int getCount()
{
return counter ;
}
// method to get object from the pool
public T getObj()
{
// declare item
T objectItem;
// check if pool has any objects
// if yes, remove the first object and return it
// also, decrease the count
if (counter > 0)
{
objectItem = objectsList[0] ;
objectsList.RemoveAt(0) ;
counter--;
return objectItem;
}
// if the pool has no objects, create a new one and return it
else
{
T obj = new T();
return obj;
}
}
// method to return object to the pool
// if counter is less than the max objects allowed, add object to the pool
// also, increment counter
public void releaseObj(T item)
{
if(counter < maxObjects)
{
objectsList.Add(item);
counter++;
}
}
}
// declaring a student class for demonstration purposes
class Student
{
private string firstName;
private int studentID;
public string getName()
{
return firstName ;
}
public void setName(string name)
{
firstName = name ;
}
public int getID()
{
return studentID ;
}
public void setID(int ID)
{
studentID = ID ;
}
}
// this class executes the program
class Program
{
static void Main(string[] args)
{
// declaring an object pool holding class Student objects
objectPool<Student> objPool = new objectPool<Student>();
Student obj = objPool.getObj();
Console.WriteLine("First object assigned");
objPool.releaseObj(obj);
int count = objPool.getCount() ;
Console.WriteLine("First object released back into the pool");
Console.WriteLine("Current count of pool: " + count);
Student obj2 = objPool.getObj() ;
Console.WriteLine("Second object assigned");
count = objPool.getCount() ;
Console.WriteLine("Current count of pool: " + count);
objPool.releaseObj(obj2);
}
}

Explanation

The following is the explanation of the code to demonstrate how object pools work:

  • Line 90: We declare an object pool named objPool to hold objects from the Student class.

  • Line 92: We assign the first object, obj. Since this is the first instance, the pool is empty; a new object is created and returned.

  • Line 94–97: We release obj back into the pool and check the pool counter. It returns 11, signifying that obj is successfully added back.

  • Lines 99–102: We create a second object, obj2, and check the pool counter. As expected, it returns 00 since the new object is taken from the pool instead of creating a new one.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved