.NET

Reusing objects with generic object pooling

Over the last couple of months I’ve been working a lot with WPF (Windows Presentation Foundation), the popular user interface framework by Microsoft.

Something that I noticed quite quickly is how expensive it can be to create WPF controls in code. It could take up to several milliseconds to create a new interface element – even simple ones. The interface I was working on had to be very flexible and could change often however, which would cause it to freeze for noticeable durations regularly, which is unacceptable.

The way I solved that problem is by using object pools:

Instead of constantly deleting old and creating new interface elements every time the interface changed, I created a collection to keep deleted instances around and reuse them when I needed new ones.

This can be done easily by simply keeping any kind of modifiable collection like a List

(though I would recommend using a stack or queue for ease of access), where we keep deleted objects until we need them again.

Today we will take a look at my implementation of a slightly more complex – yet easy to use – object pool that handles this behaviour for us – and does so for any number of different types, using generics.

Using static generics

The solution we will develop here will be entirely static. While that is less flexible than a properly object oriented object pool, it will allow us to make use of a very useful feature of C#:

Static members of generic types are not shared between multiple instances of the type, or with an example:

Given the class:

class Foo<T>
{
    public static int Bar;
}

Foo<string>.Bar and Foo<bool>.Bar are two distinct static members that can hold different values.

This means we can do the following.

static class StaticObjectPool<T>
{
    private readonly Stack<T> pool = Stack<T>();
}

This class will create stacks in which we can hold our objects – exactly one for each of the types we use it for – with all the niceties of type-safety.

Basic implementation

Our object pool class needs essentially two functionalities: adding objects, and removing them.

We implement them as follows.

public void Push(T obj)
{
    pool.Push(obj);
}
public T Pop()
{
    return pool.Pop();
}

However, there is one pitfall with this code:

If we accidentally try and get an object while the stack is empty, this will throw an exception. We could expose the number of objects in the pool, but let us instead implement the common TryGet pattern used in a number of C# classes:

public bool TryPop(out T obj)
{
    if(pool.Count > 0)
    {
        obj = pool.Pop();
        return true;
    }
    obj = default(T);
    return false;
}

In principle, this is all we really need. Our class is fully functional and can be used very easily:

// store object for later usage
StaticObjectPool<ExpensiveObject>.Push(myExpensiveObject);
// get object from pool, or create new if none there
MyExpensiveObject obj;
if(!StaticObjectPool<ExpensiveObject>.TryPop(out obj))
{
    obj = new ExpensiveObject();
}
// alternative way of getting/creating object (does not work for value types)
MyExpensiveObject obj;
StaticObjectPool<ExpensiveObject>.TryPop(out obj)
if(obj == null)
{
    obj = new ExpensiveObject();
}

Easy peasy!

Taking a closer look

Nested generics

But, if we actually take a look at the code we have just written, using our system… it is sort of ugly, is it not?

Take a look at the line StaticObjectPool<ExpensiveObject>.Push(myExpensiveObject);

Is it really necessary to define the type of the object? Can we not make our system infer the type somehow, so we can write more succinct code?

Well, actually, we can!

The problem with this code is that we need to specify the generic type so our system knows which generic class to look at. We can solve this by nesting our generic class into another non-generic one, like this:

static class StaticObjectPool
{
    private static class Pool<T>
    {
        private readonly Stack<T> pool = Stack<T>();
        public void Push(T obj)
        {
            pool.Push(obj);
        }
        public bool TryPop(out T obj)
        {
            if(pool.Count > 0)
            {
                obj = pool.Pop();
                return true;
            }
            obj = default(T);
            return false;
        }
    }
    public void Push<T>(T obj)
    {
        Pool<T>.Push(obj);
    }
    public bool TryPop<T>(out T obj)
    {
        return Pool<T>.TryPop(out obj);
    }
}

We can now use the class like this:

StaticObjectPool.Push(myExpensiveObject);
StaticObjectPool.TryPop(out myExpensiveObject);

The key point here is that C# can infer the generic type of the methods – note how the methods themselves are now generic, instead of the class – and then accesses the correct generic class for us internally.

Implementing common usage patterns

Something else that bothers me above our first usage example is how when we try and pop an object from our pool, we need a conditional statement to check whether we actually gone one, and if not create a new object. We will have to write that code every time that we access our pool.

This clearly screams for us to provide an automatic way of doing the same.

In the first case, we can use another common pattern: GetOrDefault, which will simply return us the default value of our type whenever the pool is empty:

public static T PopOrDefault<T>()
{
    T ret;
    TryPop(out ret);
    return ret;
}

This will do us little good if we are dealing with value types, but when using classes, as we most likely are when talking about expensive objects, we can now do the following:

var obj = StaticObjectPool.PopOrDefault<ExpensiveObject>()
            ?? new ExpensiveObject();

True, we again have to specify the type in our method call, but we can now do with the ?? operator what we needed an if block for before.

In fact, there is a special case in which we can make this even nicer: The case of parameterless constructors. Unfortunately C# does not provide us with the ability to define constructors in interfaces – something that could come in very handy for generic type constraints.

However, there is one exception: We can specify in our method (or type) signature that we require our generic type to have a parameterless constructor.

Given that requirement, we can then use said constructor without any knowledge about the generic type itself. This allows us to write a method as follows:

public static T PopOrNew<T>()
    where T : new()
{
    T ret;
    return TryPop(out ret) ? ret : new T();
}

which is used like this:

var obj = StaticObjectPool.PopOrNew<ExpensiveObject>();

I dare say that this may be as concise as we can make our call. Not to mention that it very clearly communicates to the reader what the code in question does – while the multiple lines above (that did after all the exact same thing) might require a moment longer to understand.

Full code

For completeness, here is the full code, with yet another small addition.

static class StaticObjectPool
{
    private static class Pool<T>
    {
        private static readonly Stack<T> pool = new Stack<T>();
        public static void Push(T obj)
        {
            lock (pool)
            {
                pool.Push(obj);
            }
        }
        public static bool TryPop(out T obj)
        {
            lock (pool)
            {
                if (pool.Count > 0)
                {
                    obj = pool.Pop();
                    return true;
                }
            }
            obj = default(T);
            return false;
        }
    }
    public static void Push<T>(T obj)
    {
        Pool<T>.Push(obj);
    }
    public static bool TryPop<T>(out T obj)
    {
        return Pool<T>.TryPop(out obj);
    }
    public static T PopOrDefault<T>()
    {
        T ret;
        TryPop(out ret);
        return ret;
    }
    public static T PopOrNew<T>()
        where T : new()
    {
        T ret;
        return TryPop(out ret) ? ret : new T();
    }
}

Note how I used a simple lock in our two main methods to make this system entirely thread-safe as well. While I did not need that feature for the issue that prompted me to write it, it was almost trivial to add.

Conclusion

I hope this has been interesting and potentially useful to you.

Drop a comment below, if anything is unclear, or you have other questions. Also make sure to let me know if you use object pooling yourself, especially if you have written your own system for it.

Also feel free to check out this follow up post where I explore how we can automate our object pooling using IDisposable and finalizers.

Enjoy the pixels!

Reference: Reusing objects with generic object pooling from our NCG partner Paul Scharf at the GameDev<T> blog.

Paul Scharf

Paul is a self-publishing game developer. He believes that C# will play an ever growing role in the future of his industry. Next to working on a variety of projects he writes weekly technical blog posts on C#, graphics, and game development in general.

Related Articles

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button