Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
What is an object pool in C#?
An object pool in C# is a software design pattern that maintains a collection of reusable objects to optimize resource usage and improve performance. Instead of constantly creating and destroying expensive objects, the pool keeps pre-initialized objects ready for use.
The object pool pattern works on two fundamental operations −
- Rent/Get: When an object is needed, it is retrieved from the pool.
- Return: When the object is no longer needed, it is returned to the pool for reuse.
Using ObjectPool<T> in .NET
.NET Core and .NET 5+ provide a built-in ObjectPool<T> through the Microsoft.Extensions.ObjectPool package. This implementation is thread-safe and efficient for high-performance scenarios.
Example
using System;
using System.Text;
using Microsoft.Extensions.ObjectPool;
class Program {
static void Main() {
// Create a policy for StringBuilder objects
var policy = new DefaultPooledObjectPolicy<StringBuilder>();
// Create an object pool
var pool = new DefaultObjectPool<StringBuilder>(policy);
// Rent an object from the pool
var sb = pool.Get();
try {
sb.Append("Hello, ");
sb.Append("Object Pool!");
Console.WriteLine("Result: " + sb.ToString());
}
finally {
// Always return the object to the pool
pool.Return(sb);
}
// Demonstrate reuse
var sb2 = pool.Get();
Console.WriteLine("Reused StringBuilder length: " + sb2.Length);
pool.Return(sb2);
}
}
The output of the above code is −
Result: Hello, Object Pool! Reused StringBuilder length: 0
Custom Object Pool Implementation
Example
using System;
using System.Collections.Concurrent;
public class SimpleObjectPool<T> where T : class, new() {
private readonly ConcurrentBag<T> _objects = new ConcurrentBag<T>();
private readonly Func<T> _objectGenerator;
public SimpleObjectPool() : this(() => new T()) { }
public SimpleObjectPool(Func<T> objectGenerator) {
_objectGenerator = objectGenerator ?? throw new ArgumentNullException(nameof(objectGenerator));
}
public T GetObject() {
if (_objects.TryTake(out T item)) {
return item;
}
return _objectGenerator();
}
public void PutObject(T item) {
_objects.Add(item);
}
}
// Example usage
class ExpensiveObject {
public string Data { get; set; }
public ExpensiveObject() {
Console.WriteLine("Creating expensive object...");
}
}
class Program {
static void Main() {
var pool = new SimpleObjectPool<ExpensiveObject>();
// First usage - creates new object
var obj1 = pool.GetObject();
obj1.Data = "First use";
Console.WriteLine("Using: " + obj1.Data);
pool.PutObject(obj1);
// Second usage - reuses existing object
var obj2 = pool.GetObject();
obj2.Data = "Second use";
Console.WriteLine("Using: " + obj2.Data);
pool.PutObject(obj2);
}
}
The output of the above code is −
Creating expensive object... Using: First use Using: Second use
Common Use Cases
- Database Connections: Pooling expensive database connection objects.
- StringBuilder Objects: Reusing StringBuilder instances to avoid memory allocation.
- HTTP Clients: Pooling HttpClient instances for web requests.
- Graphics Objects: Reusing bitmap or graphics objects in games or image processing.
- Buffer Arrays: Pooling byte arrays for I/O operations.
Benefits and Considerations
| Benefits | Considerations |
|---|---|
| Reduced object creation overhead | Memory overhead of maintaining pool |
| Lower garbage collection pressure | Thread-safety requirements |
| Predictable performance | Object state cleanup needed |
| Resource conservation | Pool size management |
Conclusion
Object pools in C# are valuable for optimizing performance by reusing expensive objects instead of creating and destroying them repeatedly. Use object pools when dealing with costly object creation, high-frequency allocations, or when you need to reduce garbage collection pressure in performance-critical applications.
