Horse Drawn Games is a small team of developers committed to creating exceptional digital games and interactive experiences. In addition to producing our own original content, we also offer services for those building their own digital products.

Type-safe object pool for Unity

Managing memory usage can be crucial for decent performance in game development, especially on memory-constrained devices like mobile phones or consoles. It’s usually best to allocate what you need up-front at startup or on level load rather than mid-game during a frame, because the default memory allocators can be slow at finding free memory blocks. Constructing objects can also be time consuming depending on the complexity of your classes.

In a garbage collected, managed language like C# you still have to worry about this. You don’t know when the garbage collector is going to clean up objects that are no longer referenced in order to reclaim unused memory. If you allocate objects regularly every frame that quickly become unused and unreferenced, you’ll probably cause regular hitches in your framerate. Also in Unity the Instantiate function call can take quite a bit of CPU time.

One technique we can use to avoid these issues is called “object pooling”. Let’s say you want to spawn a firework particle effect:

fx

Instead of instantiating the prefab whenever you need it, you could pre-instantiate a list of them and disable them. Then when you need to spawn a new firework, go through the list, find one that isn’t enabled, enable it, configure its position, and play it. When it finishes, disable it. This way you re-use firework effects instead of continually creating new objects and destroying them later.

A First Attempt

A first pass on a system like this might look as follows:

using UnityEngine;
using System.Collections.Generic;

public class BasicObjectPool : MonoBehaviour
{
    // Prefab for this object pool
    public GameObject m_prefab;

    // Size of this object pool
    public int m_size;

    public void Awake()
    {
        // Instantiate the pooled objects and disable them.
        for (var i = 0; i < m_size; i++)
        {
            var pooledObject = Instantiate(m_prefab, transform);
            pooledObject.gameObject.SetActive(false);
        }
    }

    // Returns an object from the pool. Returns null if there are no more
    // objects free in the pool.
    public GameObject Get()
    {
        if (transform.childCount == 0)
            return null;

        return transform.GetChild(0).gameObject;
    }

    // Returns an object to the pool.
    public void ReturnObject(GameObject pooledObject)
    {
        // Reparent the pooled object to us and disable it.
        var pooledObjectTransform = pooledObject.transform;
        pooledObjectTransform.parent = transform;
        pooledObjectTransform.localPosition = Vector3.zero;
        pooledObject.gameObject.SetActive(false);
    }
}

Note that our Get method returns null if there are no more objects in the pool. We could also dynamically increase the size of the pool here, but that defeats the purpose of pre-allocating the objects. It’s up to the code calling Get to check if no object is available and handle that situation. In practice you would pick a pool size that adequately covers the maximum number of objects you would like to have available at any one time. It’s not feasible to just keep spawning objects – you’ll run out of memory if you do!

This solution isn’t bad, but I have one big problem with it. The pool doesn’t know what type of component you’re pooling! This means that you have to do a GetComponent call every time you get an object out of the pool. It also means that there are no guarantees that the pool even HAS the component type you’re expecting; you can’t enforce it, so someone could mis-configure it in a prefab or a scene.

Can we do better? Yes! With generics!

Generics

Generics are a feature of the C# language. They let you design a class or write a method with a placeholder type, which means you can write classes or methods that work with any data type, and still remain type safe. Unity makes use of them, and in fact if you use Unity’s GetComponent<..>() methods you, are already using them yourself.

This line:

fooGameObject.GetComponent<FooComponent>()

gets the MonoBehaviour of type FooComponent which is on fooGameObject. How can this work? The Unity developers don’t know anything about your FooComponent. This syntax with the angled brackets indicates that the GetComponent method is a generic method which can work with any type (actually, specifically any MonoBehaviour type). When you call the method and put your type in the angled brackets, you tell the compiler to automatically generate a version of GetComponent that knows specifically about your type.

For more detailed information about generics, check out this introduction from Microsoft.

Improved Implementation

Let’s implement our object pool class using generics. First we need to define a generic version of the class that accepts a type name. We want to pool Unity components, so we’ll also add a constraint on the type which says that it must be a MonoBehaviour:

public class ObjectPool<T> : MonoBehaviour where T : MonoBehaviour

The where keyword defines the constraint. There are several different types of constraints we can specify. In our case we want the constraint that says “the type MUST derive from MonoBehaviour”.

Now that we have the class defined like this, we can use the generic type placeholder T anywhere that we want to refer to the type that the pool was created with:

public class ObjectPool<T> : MonoBehaviour where T : MonoBehaviour
{
    // Prefab for this pool. The prefab must have a component of type T on it.
    public T m_prefab;

    // Size of this object pool
    public int m_size;

    // The list of free and used objects for tracking.
    // We use the generic collections so we can give them our type T.
    private List m_freeList;
    private List m_usedList;

    public void Awake()
    {
        m_freeList = new List(m_size);
        m_usedList = new List(m_size);

        // Instantiate the pooled objects and disable them.
        for (var i = 0; i < m_size; i++)
        {
            var pooledObject = Instantiate(m_prefab, transform);
            pooledObject.gameObject.SetActive(false);
            m_freeList.Add(pooledObject);
        }
    }
}

Let’s now add two methods: one to get an object out of the pool and one to return an object back to the pool. Previously we passed GameObjects around because we didn’t know what type we would be dealing with. Now that we are using generics, we can use our placeholder T:

public T Get()
{
    var numFree = m_freeList.Count;
    if (numFree == 0)
        return null;

    // Pull an object from the end of the free list.
    var pooledObject = m_freeList[numFree - 1];
    m_freeList.RemoveAt(numFree - 1);
    m_usedList.Add(pooledObject);
    return pooledObject;
}

// Returns an object to the pool. The object must have been created
// by this ObjectPool.
public void ReturnObject(T pooledObject)
{
    Debug.Assert(m_usedList.Contains(pooledObject));

    // Put the pooled object back in the free list.
    m_usedList.Remove(pooledObject);
    m_freeList.Add(pooledObject);

    // Reparent the pooled object to us, and disable it.
    var pooledObjectTransform = pooledObject.transform;
    pooledObjectTransform.parent = transform;
    pooledObjectTransform.localPosition = Vector3.zero;
    pooledObject.gameObject.SetActive(false);
}

And we’re done! You can see the full class over on github. Now, we can’t actually add this class to a GameObject yet. As it stands, the class is just a kind of template. It doesn’t really exist as any concrete code until we declare it somewhere with a concrete type.

Let’s assume that we have an Explosion MonoBehaviour which is on a prefab:

public class Explosion : MonoBehaviour
{
    private ParticleSystem m_particleSystem;

    public bool IsAlive { get { return m_particleSystem.IsAlive(); } }

    public void Awake()
    {
        m_particleSystem = GetComponent<ParticleSystem>();
    }

    public void Spawn(Vector3 position)
    {
        gameObject.SetActive(true);
        gameObject.transform.position = position;
        m_particleSystem.Play();
    }
}

We want to create a pool of Explosion objects. To do this, we must define a new class which derives from ObjectPool with the Explosion as our type parameter:

public class ExplosionPool : ObjectPool<Explosion>
{
}

And that’s it! You can now add ExplosionPool to a GameObject, and assign a prefab to it. The ObjectPool‘s m_prefab field will appear in the inspector, and it will only allow you to drop an Explosion component on it. It’s strongly typed!

objectpool

Now to spawn an explosion, you can do this:

public void SpawnExplosion(Vector3 position)
{
    var explosion = m_explosionPool.Get();
    if (explosion == null)
    {
        // The pool is empty, so we can't spawn any more at the moment.
        return;
    }

    explosion.Spawn(position);
    m_activeExplosions.Add(explosion);
}

In the above example we also keep track of the active explosions so we can return them to the pool when they are finished:

public void Update()
{
    for (var i = 0; i < m_activeExplosions.Count - 1; i >= 0; i--)
    {
        var explosion = m_activeExplosions[i];
        if (!explosion.IsAlive)
        {
            m_activeExplosions.RemoveAt(i);
            m_explosionPool.ReturnObject(explosion);
        }
    }
}

Over on github I have a sample Unity project that demonstrates both the non-type-safe and type-safe methods. It’s a simple project that fires some particles from a pool when you click in the game window.

Feel free to hit me up on Twitter if you have any questions, or leave a comment below!

Decoding iOS crash call stacks

Wow it’s been a while since I updated the blog! I think we’re due for a web site refresh too. But first let’s talk about call stacks!

Let’s say your iOS game crashes outside of the debugger. Assuming your device is plugged into your mac, you can get the device log from Xcode by bringing up the “Devices” window via Window -> Devices. You should see a live updated log and you might be able to find your crash details in among the spammy output. But even better – if you click on “View Device Logs” you’ll see a list of apps that have crashed.

Screen Shot 2017-04-05 at 10.53.50 PM

In this example, Resynth (a game I’ve been working on for my new company Polyphonic LP) has crashed a couple of times, and I’ve selected one of the crashes.

Why did it crash? Luckily we have the full call stack. A call stack is simply a list of functions that are currently being executed by the CPU. In this case, the call stack looks like this:

Thread 0 Crashed:
0   libobjc.A.dylib               	0x000000018749ef68 objc_msgSend + 8
1   Foundation                    	0x0000000189548ba4 _NS_os_log_callback + 68
2   libsystem_trace.dylib         	0x0000000187b0f954 _NSCF2data + 112
3   libsystem_trace.dylib         	0x0000000187b0f564 _os_log_encode_arg + 736
4   libsystem_trace.dylib         	0x0000000187b0ffb8 _os_log_encode + 1036
5   libsystem_trace.dylib         	0x0000000187b13200 os_log_with_args + 892
6   libsystem_trace.dylib         	0x0000000187b1349c os_log_shim_with_CFString + 172
7   CoreFoundation                	0x0000000188a38de4 _CFLogvEx3 + 152
8   Foundation                    	0x0000000189549cb0 _NSLogv + 132
9   resynth                       	0x000000010056ac28 0x10004c000 + 5368872
10  resynth                       	0x000000010056b654 0x10004c000 + 5371476
11  resynth                       	0x000000010056bdd4 0x10004c000 + 5373396
12  resynth                       	0x00000001000b13f4 0x10004c000 + 414708
13  resynth                       	0x0000000100081c94 0x10004c000 + 220308
14  resynth                       	0x00000001000816f4 0x10004c000 + 218868
15  resynth                       	0x000000010053a33c 0x10004c000 + 5169980
16  resynth                       	0x0000000100e23404 0x10004c000 + 14513156
17  resynth                       	0x0000000100714b54 0x10004c000 + 7113556
18  resynth                       	0x0000000100714f24 0x10004c000 + 7114532
19  resynth                       	0x0000000100708054 0x10004c000 + 7061588
20  resynth                       	0x0000000100709db4 0x10004c000 + 7069108
21  resynth                       	0x000000010070a0a8 0x10004c000 + 7069864

There isn’t much symbol information; the only thing we can really see is that the NSLog function was running. But what called NSLog and what caused it to crash?

Fortunately there are several tools we can use to decode this. I’m going to cover one of them today: atos. atos converts memory addresses to symbol names, and it comes with macOS and lives in /usr/bin so it should already be in your path. It takes a couple of parameters:

atos -arch <architecture> -l <load address> -o <path to debug binary> <addresses>

We need to supply the architecture of our binary, the load address (the base address in memory where the executable was loaded), the path to a version of our binary with full debug information present, and the list of call stack addresses that we wish to translate into symbols.

If you have archived your game from Xcode, the full debug executable can be found inside the archive, in dSYMs/resynth.app.dSYM/Contents/Resources/DWARF.

Our architecture is arm64 (unless you’re running arm7 which is unlikely these days).

For this crash our load address is 0x10004c000. The load address could be anything and won’t always be the same. Sometimes the load address might not be present, and the call stack lines might look something like this:

9   resynth                       	0x000000010056ac28 resynth + 5368872

This can happen if you get your crash information from the device log view in Xcode instead of from the specific application crash view.

Here 0x000000010056ac28 is the real memory address where this particular function was loaded, and 5368872 is the offset of the function from the load address. We can therefore easily calculate the load address; it’s just 0x000000010056ac28 - 5368872 which is 0x10004C000.

Now we have everything we need, so let’s run this!

$ atos -arch arm64 -l 0x10004c000 -o resynth-debug 0x000000010056ac28 0x000000010056b654 0x000000010056bdd4
CM_NSLog(NSString*, ...) (in resynth-debug) (CloudManager.mm:17)
-[CloudManager getLongLong:] (in resynth-debug) (CloudManager.mm:171)
getLongLong (in resynth-debug) (CloudManager.mm:225)

In the interests of brevity I’ve used only the three top most addresses. This is usually enough to figure out the problem anyway!

In this case the culprit turns out to be the getLongLong Objective-C method:

- (long long) getLongLong:(NSString *)key
{
    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
    long long value = [[userDefaults objectForKey:key] longLongValue];
    DEBUG(@"CloudManager: getLongLong key=%@ value=%@", key, value);
    return value;
}

On line 5 we specify a string with the %@ format specifier, which means we should be passing in an NSObject-derived object. However, we are instead passing a long long value which causes a crash.

The fix is simple. We just convert the long long to an NSObject:

DEBUG(@"CloudManager: getLongLong key=%@ value=%@", key, @(value));