Hitting the Pool


Okay folks, it’s summer and it’s the perfect time to hit the pool! This being a game development blog, you can probably guess that I’m not talking about the filled-with-water kind of pool, but rather memory pools. Oh yeah, programmer puns. They’re the best, right?

All joking aside, pools of preallocated objects are a basic but very useful structure for controlling memory allocation in games. The basic idea is that, instead of allocating (“new-ing”) an instance of an object just before you use it, you preallocate a set number of objects ahead of time and store them in a list (pool). Later, when you actually need to use an instance of the object, you grab an unused instance off the list and initialize it with the relevant data.

Preallocating objects allows you to avoid the allocation of items at performance-critical times (say, in-game) by paying the cost up-front at a less performance-critical juncture like level-loading. On the down-side, you will usually end up paying memory for objects you will never use because it can be impossible to predict exactly how many instances of an object you may need ahead of time. At times like those, it’s useful to have a pool implementation that is flexible enough to grow to handle peak usage at runtime in addition to being preallocatable.

While avoiding memory allocations at during gameplay is a decent enough reason to use object pools, XNA provides an even more compelling reason for using them, especially on 360: the garbage collector. The garbage collector may free you from the hassle of having to track every bit of memory you allocate, but it can unfortunately be very slow. When the garbage collector runs, it needs to iterate through a significant portion of the heap to determine if anything can be destroyed to free up memory. This process can take tens of milliseconds (or even more!) which is more than enough to glitch your framerate. To make matters worse, you don’t have complete control over when the garbage collector runs, so you need to know how to work around it.

This is where object pools come into the garbage collection picture. The key to keeping the garbage collector from running during gameplay is to avoid allocating memory. One of the main keys to avoid allocating memory during gameplay is to use pools to control when the actual allocations occur. Basically, if you preallocate objects, you don’t have to worry about kicking off garbage collections when you use them and this can help you keep your as framerate smooth as possible.

To fulfill my object pooling needs, I started with this implementation by Jason Mitchell. It has the flexibility to grow at runtime which is great for prototyping. I added a function to preallocate a given number of instances so that, once I have my allocation needs figured out, I can allocate the appropriate number of instances at load time to keep my memory allocations during gameplay to a bare minimum.

As always, if you want the code, I’m happy to share:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

//Pool Class from http://jason-mitchell.com/wp7/generic-pool-class-for-reusing-objects/
//Usage Example:
//  private Pool<GameObject> objectPool = new Pool<GameObject>(() => new GameObject()); 
//  public void Initialize()
//  {
//      GameObject gameObject = objectPool.GetFreeItem();
//      gameObject.Initialize();
//  }

namespace Misc
{
    public class Pool<T>
    {
        private readonly List<T> items = new List<T>();
        private readonly Queue<T> freeItems = new Queue<T>();

        private readonly Func<T> createItemAction;

        public Pool(Func<T> createItemAction)
        {
            this.createItemAction = createItemAction;
        }

        public void Preallocate(int itemCount)
        {
            T[] items = new T[itemCount];
            for (int i = 0; i < itemCount; ++i)
            {
                items[i] = GetFreeItem();
            }

            for (int i = 0; i < itemCount; ++i)
            {
                FlagFreeItem(items[i]);
            }
        }

        public void FlagFreeItem(T item)
        {
            freeItems.Enqueue(item);
        }

        public T GetFreeItem()
        {
            if (freeItems.Count == 0)
            {
                T item = createItemAction();
                items.Add(item);

                return item;
            }

            return freeItems.Dequeue();
        }

        public List<T> Items
        {
            get { return items; }
        }

        public void Clear()
        {
            items.Clear();
            freeItems.Clear();
        }
    }
}
Share this Article:
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • Print