Unity Mono Runtime – The Truth about Disposable Value Types

When I started making games using Unity, after almost 10 years of C# development, I was very concerned to acknowledge that foreach loops are highly avoided in Unity because they allocate unnecessary memory on the heap. Personally I love the clean syntax of a foreach. It aids readably and clarity and it also increases the abstraction level. However a very clear and neat explanation of the memory issue problem can be found in a blog article posted on Gamasutra by Wendelin Reich.

From Wendelin’s analysis it emerged that the version of the Mono compiler adopted in Unity has a different behaviour from Microsoft implementation. In particular enumerators, which are usually implemented in the .NET framework as mutable value types, are boxed by the compiler, causing an unnecessary generation of garbage. Boxing is the process of converting a value type (allocated on the stack) into a reference type, thus allocating a new instance on the heap. 

This aspect is really interesting as well as dangerous. As you probably know memory leaks in C# will trigger the GC (garbage collector) too often causing performance spikes and frame drops in your game.

However I think an explanation of why value types are boxed is missing from Wendelin’s article. A very common idea between game developers is that the Mono runtime in Unity has a bug.

To be really honest with you don’t necessarily have to know the reason behind this behaviour. It’s more than enough to know that using foreach loops generate garbage so you can avoid them. However I always have been extremely curious like a cat that checks out an empty box. I believe that curiosity is the biggest source of power for a developer. So if you’re like me, curious to know what’s going on in the old Mono compiler just keep on reading🙂

Foreach loops are basically syntactic sugar. The C# compiler processes a foreach loop like the following:

void Update(){
   var fibonacci
      = new List<int>{ 1, 1, 2, 3, 5, 8, 13 };

   foreach(var f in fibonacci) {
     Console.WriteLine(f);
   }
}

into something else that essentially looks like this code:

using (var enumerator = fibonacci.GetEnumerator())
{
   while(enumerator.MoveNext())
   {
     var current = enumerator.Current;
     Console.WriteLine(current);
   }
}

Under the hood the C# compiler uses an Iterator block (based on the Iterator design pattern). The enumerator of the collection being iterated must implement a MoveNext() Dispose() and Reset() method and it must expose the property Current, that holds a reference to the current element. In the .NET framework enumerators (with an exception for KeyCollection and ArrayList) are generally mutable value-types that implements the interface IEnumerator or IEnumerator<T> for generic collections and the interface IDisposable. As you can see the foreach hides the complexity of enumerators, which is really handy!

However the using statement is syntactic sugar too (too many calories for a foreach don’t you think?😀 ). Its purpose is to obtain a resource, to execute a statement, and then to dispose the resource. The C# compiler translates the using statement into something different. To know how the final code looks like we have two options:

  1. Look at the generated IL (Intermediate Language) by decompiling the function that contains the foreach loop (and thus the using).
  2. Look at the C# specification language document.

Let’s go with the first option and see how the IL code looks like in figure 1. To decompile your assemblies you can either use ILSpy on Windows (which I highly recommend) or monodis, the equivalent command-line Mono implementation of ILDASM, available on MacOS and Linux too.

ILForeach

Figure 1 – The IL code of our foreach loop

As expected the value-type Enumerator is boxed (bottom center in figure 1) and then allocated on the heap. This is of course not a news for any experienced Unity developer. This issue has been addressed in a plethora of articles online (just to mention another good one: REDUCING MEMORY USAGE IN UNITY, C# AND .NET/MONO). However I’m pretty confident that not many developers are able to explain why.

As mentioned earlier, a lot of Unity devs know about this behaviour as a bug in the version 2.6 of the Mono compiler…but is it really a bug? Before jumping to conclusion I’d invite you to have a look at the C# specification document (remember, our option 2), specifically the chapter about using statement in case of non-nullable value types.

From chapter 8.13 of the C# 5 specification document:

A using statement of the form

using (ResourceType resource = expression) statement

corresponds to one of three possible expansions. When ResourceType is a non-nullable value type, the expansion is

{
   ResourceType resource = expression;
   try {
     statement;
   } finally {
     ((IDisposable)resource).Dispose();
   }
}

Have you notice anything strange in the code above? Look again…at the finally block. resource is first cast into an a IDisposable object and then the Dispose method is called. Wait a second…IDisposable is an interface…what happens if you cast a value type  into an interface type? The value-type is boxed and allocated on the heap!!!! Boxing makes a copy of the resource, and it is the copy which is disposed, and therefore the copy which is mutated. This is a way to avoid mutating the value type, moreover, within a using statement it is not possible to mutate (i.e. manually changing the fields of) a value type struct.

Now I would like to ask you one more time: is it a bug in the old Mono compiler? It looks like it is definitely NOT. The poor and blamed Mono compiler does exactly what the C# specification states. At this stage you’re probably wondering if the Microsoft C# compiler behaves differently. Let’s have a look at the IL of the same assembly used above but compiled with the Microsoft compiler:

ILForeach2

Figure 2 – IL code of a foreach loop in the Microsoft C# compiler

Surprisingly the disposed resource is not boxed, instead a constrained callvirt is forced in order to avoid boxing. Eric Lippert, a Principal Developer at Microsoft on the C# compiler team and a member of the C# language design team up until 2013, wrote an interesting article on his blog on the topic. It emerges from his article that the Microsoft C# compiler performs an optimisation: if it detects that the Dispose method is exposed directly on the value type then it effectively generates a call to:

finally {
   resource.Dispose();
}

The careful reader might notice that this optimisation performed by the compiler is not reported in the C# specification document. In fact, in an answer I found on StackOverflow Eric admits that the optimisation emitted — of using constrained callvirt to skip the boxing when possible — is actually strictly speaking a violation of the C# specification.

This is the reason why in the Microsoft C# compiler (as well as in the latest Mono compiler) the use of foreach, or to be technically correct, the use of disposable structs within a using statement doesn’t generate garbage.

What the old Mono compiler is missing is a specific optimisation, and unfortunately even if Unity has stated that an upgrade to the new Mono compiler is planned, they won’t do it until IL2CPP will be compatible among all mobile platforms.

However I came up with a solution that makes foreach loops garbage free with a lot of different collection (included dictionaries!). I used a third party collection library called C5. C5 is a library of generic collection classes for C# and other CLI languages. It implements a lot of data structures not provided by the standard .Net Framework, such as persistent tree data structures, heap based priority queues, hash indexed array lists and linked lists, and events on collection changes. If you want to have a look here is the link on the GitHub page of the project, and if you want to know more you’ll find an explanation on the new memory safe model I implemented in this thread of the Unity forum I posted a while ago.

That’s all folks! I hope you enjoyed the article, feel free to drop me an email if you have any question or leave a comment if you prefer. And don’t forget to follow me on Twitter!

See you soon!

6 thoughts on “Unity Mono Runtime – The Truth about Disposable Value Types

      1. To be honest, I’m very looking forward for IL2CPP, especially for desktop platform. Not everything in Unity may be implemented as CPP plugin besides plugins must be adjusted to different platforms.
        I really hope, that IL2CPP will remove these spikes related to garbage collector and other memory-related problems.

        Like

      2. My previous post has vanished, so I’ll repeat.

        I’m looking forward for robust IL2CPP, especially for desktop platform. Plugins, which are nice cannot replace the whole Unity code. Besides, separate plugin must be created for different platform. I really hope, that introducing IL2CPP will replace this garbage collector problems and generally, memory handling issues.

        Liked by 1 person

      3. I agree with you, however you should always be “sensible” with your memory management and always try to keep the number of collections to a minimum (through object pooling for example). In general yeah I’m looking forward to it too for when the IL2CPP will come to a stable point across all platform…especially on consoles!🙂

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s