0 Unity and the Garbage Collector

This is something I knew I had to deal with sooner or later. Not that this is the right moment to start worrying about memory or performance, but I felt the need to at least understand how this is going to affect the game when it comes the time.

I like to write declarative code and C# is very good at it, which is kind of evil if you ask me. In imperative languages you write code that describes how things have to be done. In declarative languages you write code that describes what's to be done no matter how, which basically means: the more you move away from imperative towards declarative, the more you allow your programming language, run-time or compiler do things its way, not yours.

In the case of Mono for Unity, letting it to do things its way will result in hundreds of thousands of little memory allocations, which is not a big deal since allocating memory on these platforms is really cheap, The problem is that this massive amount of allocations causes the garbage collector to kick-in quite often. While garbage collection is not a bad thing in itself, it's definitely something you want to avoid at all costs in FPS-sensitive games.

There are three main sources of declarative awesomeness that will feed the garbage collector heavily:

1. Closures


Every time a closure is called, the CLR will allocate memory to create an object which contains all the captured state. Place this within a tight loop and there you have it. Since I love the succint and concise code you can write with them, I tried to get around this limitation. I came up with a solution which consists of just stripping out the state and turning them into mere anonymous functions like this:

/// <summary>
/// Turning a closure into an anonymous function
/// </summary>
public void DoSomethingstring _name )
{
    // this will capture the parameter _name, thus creating an object
    Closure( () => _name );
    
    // this version will 'capture' _name as a parameter, 
    // thus turning the closure into a mere local anonymous function
    ClosureNOT_name_n => _n );
}
 
public void ClosureFunc<string> _getStrFn )
{
    var str = _getStrFn();
    // ...
}
 
public void ClosureNOTstring _strFunc<stringstring> _getStrFn )
{
    var str = _getStrFn_str );
    // ...
}


2. The 'foreach' keyword


It's hard to imagine how much evil is hidden under this keyword. Unless the underlying type is known at compile time to be an array, two things will happen:

-Due to a bug, each call to foreach (not every iteration!) will cause the returned Enumerator object
to be boxed, thus eating 24 bytes of memory in the way. This is an ancient known bug but it's still not fixed in Unity 4.6

-For every iteration, the 'MoveNext()' function is called, which performs some kind of validation. A lot of people will argue that this is not an issue, but in my case, using iterators within high-frequency functions (which is quite common in video-games) will kill the frame rate.

3. LINQ:


Using LINQ extension methods is just like using 1. and 2. but on steroids. Nearly every function in there will not only allocate closures and foreach calls, but also a lot of temporary arrays and lists.

If you want to be safe, try to stay away from the declarative part of C# and just make your sensible code look like C++.