Gamasutra: The Art & Business of Making Gamesspacer
arrowPress Releases
September 1, 2014
PR Newswire
View All
View All     Submit Event





If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 
C# Memory Management for Unity Developers (part 1 of 3)
by Wendelin Reich on 11/09/13 11:57:00 am   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

[Note: This post presupposes 'intermediate' knowledge of C# and Unity.]

I'm going to start this post with a confession. Although raised as a C/C++ developer, for a long time I was a secret fan of Microsoft's C# language and the .NET framework. About three years ago, when I decided to leave the Wild West of C/C++-based graphics libraries and enter the civilized world of modern game engines, Unity stood out with one feature that made it an obvious choice for myself. Unity didn't require you to 'script' in one language (like Lua or UnrealScript) and 'program' in another. Instead, it had deep support for Mono, which meant all your programming could be done in any of the .NET languages. Oh joy! I finally had a legitimate reason to kiss C++ goodbye and have all my problems solved by automatic memory managment. This feature had been built deeply into the C# language and was an integral part of its philosophy. No more memory leaks, no more thinking about memory management! My life would become so much easier.

Don't show this to your players.

If you have even the most casual acquaintance with Unity and/or game programming, you know how wrong I was. I learned the hard way that in game developement, you cannot rely on automatic memory managment. If your game or middleware is sufficiently complex and resource-demanding, developing with C# in Unity is therefore a bit like walking a few steps backwards in the direction of C++.  Every new Unity developer quickly learns that memory management is a problematic issue that cannot simply be entrusted to the Common Language Runtime (CLR). The Unity forums and many Unity-related blogs contain several collections of tips and best practices concerning memory. Unfortunately, not all of these are based on solid facts, and to the best of my knowledge, none of them are comprehensive. Furthermore, C# experts on sites such as Stackoverflow often seem to have little patience for the quirky, non-standard problems faced by Unity developers. For these reasons, in this and the following two blog posts, I try to give an overview and hopefully some in-depth knowlege on Unity-specific memory management issues in C#.

  • This first post discusses the fundamentals of memory management in the garbage-collected world of .NET and Mono. I also discuss some common sources of memory leaks.
  • The second looks at tools for discovering memory leaks. The Unity Profiler is a formidable tool for this purpose, but it's also expensive. I therefore discuss .NET disassemblers and the Common Intermediate Language (CIL) to show you how you can discover memory leaks with free tools only.
  • The third post discusses C# object pooling. Again, the focus is on the specific needs that arise in Unity/C# development.

I'm sure I've overlooked some important topics - mention them in the comments and I may write them up in a post-script.

Limits to garbage collection

Most modern operating systems divide dynamic memory into stack and heap (1, 2), and many CPU architectures (including the one in your PC/Mac and your smartphone/tablet) support this division in their instruction sets. C# supports it by distinguishing value types (simple built-in types as well as user-defined types that are declared as enum or struct) and reference types (classes, interfaces and delegates). Value types are allocated on the stack, reference types on the heap. The stack has a fixed size which is set at the start of a new thread. It's usually small - for instance, .NET threads on Windows default to a stack size of 1Mb. This memory is used to load the thread's main function and local variables, and subsequently load and unload functions (with their local variables) that are called from the main one. Some of it may be mapped to the CPU's cache to speed things up. As long as the call depth isn't excessively high or your local variables huge, you don't have to fear a stack overflow. And you see that this usage of the stack aligns nicely with the concept of structured programming.

If objects are too big to fit on the stack, or if they have to outlive the function they were created in, the heap comes into play. The heap is 'everything else' - a section of memory that can (usually) grow as per request to the OS, and over which the program rules as it wishes. But while the stack is almost trivial to manage (just use a pointer to remember where the free section begins), the heap fragments as soon as the order in which you allocate objects diverges from the order in which you deallocate them. Think of the heap as a Swiss cheese where you have to remember all the holes! Not fun at all. Enter automatic memory management. The task of automated allocation - mainly, keeping track of all the holes in the cheese for you - is an easy one, and supported by virtually all modern programming languages. Much harder is the task of automatic deallocation, especially deciding when an object is ready for deallocation, so that you don't have to.

This latter task is called garbage collection (GC). Instead of you telling your runtime environment when an object's memory can be freed, the runtime keeps track of all the references to an object and is thereby able to determine - at certain intervals - when an object cannot possibly be reached anymore from your code. Such an object can then be destroyed and it's memory gets freed. GC is still actively researched by academics, which explains why the GC architecture has changed and improved significantly in the .NET framework since version 1.0. However, Unity doesn't use .NET but it's open-source cousin, Mono, which continues to lag behind it's commercial counterpart. Furthermore, Unity doesn't default to the latest version (2.11 / 3.0) of Mono, but instead uses version 2.6 (to be precise, 2.6.5 on my Windows install of Unity 4.2.2 [EDIT: the same is true for Unity 4.3]). If you are unsure about how to verify this yourself, I will discuss it in the next blog post.

One of the major revisions introduced into Mono after version 2.6 concerned GC. New versions use generational GC, whereas 2.6 still uses the less sophisticated Boehm garbage collector. Modern generational GC performs so well that it can even be used (within limits) for real-time applications such as games. Boehm-style GC, on the other hand, works by doing an exhaustive search for garbage on the heap at relatively 'rare' intervals (i.e., usually much less frequently than once-per-frame in a game). It therefore has an overwhelming tendency to create drops in frame-rate at certain intervals, thereby annoying your players. The Unity docs recommend that you call System.GC.Collect() whenever your game enters a phase where frames-per-second matter less (e.g., loading a new level or displaying a menu). However, for many types of games such opportunities occur too rarely, which means that the GC might kick in before you want it too. If this is the case, your only option is to bite the bullet and manage memory yourself. And that's what the remainder of this post and the following two posts are about!

Becoming your own Memory Manager

Let's be clear about what it means to 'manage memory yourself' in the Unity / .NET universe. Your power to influence how memory is allocated is (fortunately) very limited. You get to choose whether your custom data structures are class (always allocated on the heap) or struct (allocated on the stack unless they are contained within a class), and that's it. If you want more magical powers, you must use C#'s unsafe keyword. But unsafe code is just unverifiable code, meaning that it won't run in the Unity Web Player and probably some other target platforms. For this and other reasons, don't use unsafe. Because of the above-mentioned limits of the stack, and because C# arrays are just syntactic sugar for System.Array (which is a class), you cannot and should not avoid automatic heap allocation. What you should avoid are unnecessary heap allocations, and we'll get to that in the next (and last) section of this post.

Your powers are equally limited when it comes to deallocation. Actually, the only process that can deallocate heap objects is the GC, and its workings are shielded from you. What you can influence is when the last reference to any of your objects on the heap goes out of scope, because the GC cannot touch them before that. This limited power turns out to have huge practical relevance, because periodic garbage collection (which you cannot suppress) tends to be very fast when there is nothing to deallocate. This fact underlies the various approaches to object pooling that I discuss in the third post.

Common causes of unnecessary heap allocation

Should you avoid foreach loops?

A common suggestion which I've come across many times in the Unity forums and elsewhere is to avoid foreach loops and use for or while loops instead. The reasoning behind this seems sound at first sight. Foreach is really just syntactic sugar, because the compiler will preprocess code such as this:

foreach (SomeType s in someList)
    s.DoSomething();

...into something like the the following:

using (SomeType.Enumerator enumerator = this.someList.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        SomeType s = (SomeType)enumerator.Current;
        s.DoSomething();
    }
}

In other words, each use of foreach creates an enumerator object - an instance of the System.Collections.IEnumerator interface - behind the scenes. But does it create this object on the stack or on the heap? That turns out to be an excellent question, because both are actually possible! Most importantly, almost all of the collection types in the System.Collections.Generic namespace (List<T>, Dictionary<K, V>, LinkedList<T>, etc.) are smart enough to return a struct from from their implementation of GetEnumerator()). This includes the version of the collections that ships with Mono 2.6.5 (as used by Unity).

[EDIT] Matthew Hanlon pointed my attention to an unfortunate (yet also very interesting) discrepancy between Microsoft's current C# compiler and the older Mono/C# compiler that Unity uses 'under the hood' to compile your scripts on-the-fly. You probably know that you can use Microsoft Visual Studio to develop and even compile Unity/Mono compatible code. You just drop the respective assembly into the 'Assets' folder. All code is then executed in a Unity/Mono runtime environment. However, results can still differ depending on who compiled the code! foreach loops are just such a case, as I've only now figured out. While both compilers recognize whether a collection's GetEnumerator() returns a struct or a class, the Mono/C# has a bug which 'boxes' (see below, on boxing) a struct-enumerator to create a reference type.

So should you avoid foreach loops?

  • Don't use them in C# code that you allow Unity to compile for you.
  • Do use them to iterate over the standard generic collections (List<T> etc.) in C# code that you compile yourself with a recent compiler. Visual Studio as well as the free .NET Framework SDK are fine, and I assume (but haven't verified) that the one that comes with the latest versions of Mono and MonoDevelop is fine as well.

What about foreach-loops to iterate over other kinds of collections when you use an external compiler? Unfortunately, there's is no general answer. Use the techniques discussed in the second blog post to find out for yourself which collections are safe for foreach[/EDIT]

Should you avoid closures and LINQ?

You probably know that C# offers anonymous methods and lambda expressions (which are almost but not quite identical to each other). You can create them with the delegate keyword and the => operator, respectively. They are often a handy tool, and they are hard to avoid if you want to use certain library functions (such as List<T>.Sort()) or LINQ.

Do anonymous methods and lambdas cause memory leaks? The answer is: it depends. The C# compiler actually has two very different ways of handling them. To understand the difference, consider the following small chunk of code:

int result = 0;
    
void Update()
{
    for (int i = 0; i < 100; i++)
    {
        System.Func<int, int> myFunc = (p) => p * p;
        result += myFunc(i);
    }
}

As you can see, the snippet seems to create a delegate myFunc 100 times each frame, using it each time to perform a calculation. But Mono only allocates heap memory the first time the Update() method is called (52 Bytes on my system), and doesn't do any further heap allocations in subsequent frames. What's going on? Using a code reflector (as I'll explain in the next blog post), one can see that the C# compiler simply replaces myFunc by a static field of type System.Func<int, int> in the class that contains Update(). This field gets a name that is weird but also revealing: f__am$cache1 (it may differ somewhat on you system). In other words, the delegator is allocated only once and then cached.

Now let's make a minor change to the definition of the delegate:

        System.Func<int, int> myFunc = (p) => p * i++;

By substituting 'i++' for 'p', we've turned something that could be called a 'locally defined function' into a true closure. Closures are a pillar of functional programming. They tie functions to data - more precisely, to non-local variables that were defined outside of the function. In the case of myFunc, 'p' is a local variable but 'i' is non-local, as it belongs to the scope of the Update() method. The C# compiler now has to convert myFunc into something that can access, and even modify, non-local variables. It achieves this by declaring (behind the scenes) an entirely new class that represents the reference environment in which myFunc was created. An object of this class is allocated each time we pass through the for-loop, and we suddenly have a huge memory leak (2.6 Kb per frame on my computer).

Of course, the chief reason why closures and other language features where introduced in C# 3.0 is LINQ. If closures can lead to memory leaks, is it safe to use LINQ in your game? I may be the wrong person to ask, as I have always avoided LINQ like the plague. Parts of LINQ apparently will not work on operating systems that don't support just-in-time compilation, such as iOS. But from a memory aspect, LINQ is bad news anyway. An incredibly basic expression like the following:

int[] array = { 1, 2, 3, 6, 7, 8 };

void Update()
{
    IEnumerable<int> elements = from element in array
                    orderby element descending
                    where element > 2
                    select element;
    ...
}

... allocates 68 Bytes on my system in every frame (28 via Enumerable.OrderByDescending() and 40 via Enumerable.Where())! The culprit here isn't even closures but extension methods to IEnumerable: LINQ has to create intermediary arrays to arrive at the final result, and doesn't have a system in place for recycling them afterwards. That said, I am not an expert on LINQ and I do not know if there are components of it that can be used safely within a real-time environment.

Coroutines

If you launch a coroutine via StartCoroutine(),  you implicitly allocate both an instance of Unity's Coroutine class (21 Bytes on my system) and an Enumerator (16 Bytes). Importantly, no allocation occurs when the coroutine yield's or resumes, so all you have to do to avoid a memory leak is to limit calls to StartCoroutine() while the game is running.

Strings

No overview of memory issues in C# and Unity would be complete without mentioning strings. From a memory standpoint, strings are strange because they are both heap-allocated and immutable. When you concatenate two strings (be they variables or string-constants) as in:

void Update()
{
    string string1 = "Two";
    string string2 = "One" + string1 + "Three";
}

... the runtime has to allocate at least one new string object that contains the result. In String.Concat() this is done efficiently via an external method called FastAllocateString(), but there is no way of getting around the heap allocation (40 Bytes on my system in the example above). If you need to modify or concatenate strings at runtime, use System.Text.StringBuilder.

Boxing

Sometimes, data have to be moved between the stack and the heap. For example, when you format a string as in:

string result = string.Format("{0} = {1}", 5, 5.0f);

... you are calling a method with the following signature:

public static string Format(
	string format,
	params Object[] args
)

In other words, the integer "5" and the floating-point number "5.0f" have to be cast to System.Object when Format() is called. But Object is a reference type whereas the other two are value types. C# therefore has to allocate memory on the heap, copy the values to the heap, and hand Format() a reference to the newly created int and float objects. This process is called boxing, and its counterpart unboxing.

This behavior may not be a problem with String.Format() because you expect it to allocate heap memory anway (for the new string). But boxing can also show up at less expected locations. A notorious example occurs when you want to implement the equality operator "==" for your home-made value types (for example, a struct that represents a complex number). Read all about how to avoid hidden boxing in such cases here.

Library methods

To wind up this post, I want to mention that various library methods also conceal implicit memory allocations. The best way to catch them is through profiling. Two interesting cases which I've recently come across are these:

  • I wrote earlier that a foreach-loop over most of the standard generic collections does not result in heap allocations. This holds true for Dictionary<K, V> as well. However, somewhat mysteriously, Dictionary<K, V>.KeyCollection and Dictionary<K, V>.ValueCollection are classes, not structs, which means that "foreach (K key in myDict.Keys)..." allocates 16 Bytes. Nasty!
  • List<T>.Reverse() uses a standard in-place array reversal algorithm. If you are like me, you'd think that this means that it doesn't allocate heap memory. Wrong again, at least with respect to the version that comes with Mono 2.6. Here's an extension method you can use instead which may not be as optimized as the .NET/Mono version, but at least manages to avoid heap allocation. Use it in the same way you would use List<T>.Reverse():
public static class ListExtensions
{
    public static void Reverse_NoHeapAlloc<T>(this List<T> list)
    {
        int count = list.Count;

        for (int i = 0; i < count / 2; i++)
        {
            T tmp = list[i];
            list[i] = list[count - i - 1];
            list[count - i - 1] = tmp;
        }
    }
}

***

There are other memory traps which could be written about. However, I don't want to give you any more fish, but teach you how to catch your own fish. Thats what the next post is about!


Related Jobs

InnoGames GmbH
InnoGames GmbH — Hamburg, Germany
[09.01.14]

Software Developer JavaScript (m/f)
InnoGames GmbH
InnoGames GmbH — Hamburg, Germany
[09.01.14]

Backend Developer Marketing / CRM (m/f)
InnoGames GmbH
InnoGames GmbH — Hamburg, Germany
[09.01.14]

Software Developer Flash (m/f)
InnoGames GmbH
InnoGames GmbH — Hamburg, Germany
[09.01.14]

Mobile Developer iOS (m/f)






Comments


Mihai Cozma
profile image
Very nice write-up. I also switched for C# from C/C++ but not in game development context (so what I've learned dealing with Microsoft's implementation was a nice thing to transfer to Unity). While the memory management is different indeed, the stuff that triggers or not memory allocations described in this article are mostly working as their Microsoft counterparts.

While there are some hidden stuff (as you make a point in the Library example), I think usually keeping the allocations out of functions that get called often (i.e. Update() and the like) will be enough for making sure not too many allocations are happening. This usually excludes the scenario where the game takes up to much memory and Unity is forced to free up stuff in the middle of gameplay.

Using Destroy instead of Dispose is also a good strategy to mark objects for deletion and letting Unity decide when to do it as it is has more knowledge about the nature of the application (i.e. a game engine) than the garbage collector itself.

One thing I would add are Unity's default GUI implementation, which is notorious for creating objects and filling up memory which in turn leads to triggering GC when you really don't want it to happen.

Andy Gibson
profile image
Thanks for taking time to share this stuff - well written and really useful. I'm looking forward to #2 and #3 ;)

William Ravaine
profile image
Great post, it gives a good summary of the various low-level areas to keep an eye on while developing on Unity.

In several places in this article you mention "memory leaks" (e.g. "we suddenly have a huge memory leak (2.6 Kb per frame on my computer)" in the section on LINQ & closures, and also in the coroutines section). Did you actually mean heap memory allocations?

Wendelin Reich
profile image
Good question! In C/C++, a memory leak is a heap allocation that doesn't have a corresponding deallocation. Technically, such a situation cannot happen in C#, because deallocation isn't your job anyway. But as I try to explain in the article, the reality of game development forces you to avoid garbage collections like the plague.

So for the purposes of game development, my definition of a 'memory leak' would be: a heap allocation that is (1) unintentional and (2) where all references go out of scope before the game ends.

William Ravaine
profile image
Thanks for the clarification on your terminology, Wendelin.

What you refer to as "memory leak" I actually split in two different issues:
1) allocated memory that is never freed/released and thus reduces the amount of total memory available to your application over its lifetime
2) garbage collection spikes caused by wasteful/unintentional memory allocations

The issue #1 is what I understand "memory leak" to mean. In C++ the main culprit would be forgetting to call delete/free while in C# it would be caused by having some references left to that object (circular references, unregistered delegates, etc...).

Harald Csaszar
profile image
Just to adress some common misconceptions about how garbage collection works (at least the Boehm GC in Mono 2.6.5):

Circular references per se are no problem.
Simplified: when an object is not 'reachable', it will get collected. It's not reference-count based, as one might incorrectly assume.
In 3 sentences: http://bit.ly/1cVNDym

It's like a chain of people hanging from a cliff, if one let's go it doesn't matter how many of the falling people are holding on to each other.

What matters however, is whether you are holding a strong references (in contrast to a WeakReference http://bit.ly/1j5sz5X) where semantically you are just registering as a subscriber (or observer, whatever you call it) and keep the publisher (object of interest) alive after it should have been deleted and all subscribers unregistered. Also beware of other cross-references for 'optimization reasons'.. Maybe it helps to think of each reference in 'owning reference' vs 'weak reference' terms to keep things well organized.

Casey Labine
profile image
> "Technically, such a situation cannot happen in C#, because deallocation isn't your job anyway."

This may be true in Unity, but it's not true of C# generally. IDisposable and associated constructs like the 'using' statement exist for exactly this reason.

Wendelin Reich
profile image
IDisposable, using etc. don't exist to allow you to deallocate (unregister etc.) heap memory. Garbage collection is a language feature of C#, this has nothing to do with Unity.

Eric Reis
profile image
I want to add here that it is possible to have a somewhat "memory leak" in Unity, too - specially when you're new to everything.

A few examples, when using renderer.material, Unity will create a material for that renderer that they ask you to unload it by yourself. It can be unloaded with resources unloading methods, but that is just like garbage collecting.

Another one, is when you create on code an object that Unity also keeps tracks of (textures, for example). Even if you have no more references to it, it lies in the domain of Unity's memory and is thus allocated. I'm not sure that resources unloading can detect all of the possible cases.

There are other pitfalls involving 'Resources' management, audio and also poor (as in unskillful) uses of the WWW class (that is also IDisposable. I didn't know what this meant, the manual didn't say it and the examples don't call Dispose())).

Unity is a great tool, but it is good to be aware that you will have to think in terms of c# memory and Unity memory to avoid 'out of memory' crashes. You'll end up worrying on deallocation as well as not feeding the GC monster.

Edit: I'm new to Unity4 so I don't know if all above remains true

Casey Labine
profile image
That's exactly why they exist. Specifically, IDisposable is for objects with unmanaged components, which fall outside the purview of the GC. You may be thinking of Finalize, which allows you to implement your disposal logic for the GC to execute later. IDisposable doesn't work that way -- it frees unmanaged resources immediately.

http://msdn.microsoft.com/en-us/library/b1yfkh5e%28v=vs.110%29.as
px

Martin Bell
profile image
+1
Confusing misuse of the generally accepted term 'memory leak'.

Matthew Hanlon
profile image
Are you sure about foreach? Having a simple dictionary (both key & value types as int for example) and looping it in the Update function:

void Update()
{
foreach(var t in test)
{
}
}

causes 28 bytes allocation per frame according to the unity profiler. Getting the enumerator and using MoveNext() on the other hand causes no allocation.

Wendelin Reich
profile image
Thanks Matthew, you are right, and you just found a nasty discrepancy between the C# *compilers* that are used by Unity (via Mono 2.6.5) and by MS Visual Studio (via .NET). I just investigated it, and here's what I found:

The MS compiler generates code that doesn't do any heap allocation, as it shouldn't. But the Mono compiler gets confused. It recognizes correctly that the enumerator object returned by Dictionary(K, V).GetEnumerator is a struct, and so doesnt allocate memory for it. But after the loop is through, and before it calls the Dispose method of the enumerator, it seems to assume that the Dispose method presupposes a class and boxes the enumerator! What a waste...

I focused only on Unity/Mono shortcomings that are due to its version of the .NET library, and ignored the ones that are caused by the inferior compiler. The funny thing is that they don't matter for Mono-compatible code that's compiled in Visual Studio.

I will correct that in the article. Thanks again!

Matthew Hanlon
profile image
Thanks for looking into the reason behind that discrepancy, interesting stuff.

Matt Benic
profile image
Interesting catch Wendelin. I know it's long shot, but I've added a feature request on feedback.unity3d.com for an update to the compiler and runtime (referencing this article), please vote for it:
http://feedback.unity3d.com/suggestions/update-built-in-mono-comp
iler-and-runtime-to-a-newer-version

Wendelin Reich
profile image
Great initiative Matt, hope it catches on. Unfortunately, I used up all of my 10 votes a long time ago... :-)

Dustin Chertoff
profile image
Great article! Bookmarked for future reference. Looking forward to the next two!

Curtiss Murphy
profile image
Great article on C# nuances with Unity. Looking forward to the rest.

Pavel Fadrhonc
profile image
So if Unity would ship with newer Mono compiler, those problems would be gone? If so, does anybody has any information when is Unity planning to do this and why it is not trivial for them to do that?

Wendelin Reich
profile image
Actually, the garbage collector in the current version of the Microsoft .NET framework and the one in the latest version of Mono are not the same, and I haven't tested the latter. Also, I wouldn't count on it working on every last platform supported by Unity.

The problem with garbage collectors in general is that they are very complex and very intransparent to the user (programmer). If you are worried that even a rare drop in frames-per-second will brake the immersion of your players, you may be better off avoiding deallocations as much as possible.

Kujel s
profile image
First great article and I look forward to parts two and three and second see below.

Now if I understand this correctly this first example is going to fragment the heap less then the second example and thus provide a smoother performence.
ex1:
Vector2 temp = new Vector2();
for(int i = 0; i < size; i++)
{
temp.Y += i * val;
spriteBatch.DrawString(font, text, temp, Color.White);
}
ex2:
for(int i = 0; i < size; i++)
{
spriteBatch.DrawString(font, text, new Vector2(0, i * val), Color.White);
}
I ask because when I first started using C# I'd use ex2 and later switched to ex1 cause I assumed it would be faster. I just want to be sure I actually understand what the article is saying and to confirm my assumption. I now tend to avoid making allocations inside loops whenever possible to speed up performence and I'd hate it if I'd been making a noob mistake all this time :p

Wendelin Reich
profile image
Actually, Vector2 is a struct, so neither example allocates heap memory.

Apart from that, I'm not so sure which example is slower. You can find out yourself by using the Stopwatch class. (http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwa
tch(v=vs.110).aspx).

PS: I think the "+=" in ex1 should be "=", no?

Kujel s
profile image
I'd always assumed Vector2 was a class not a struct but I'd never really checked the documentation :p.

PS: you're right, I should of proof read my code examples a little closer.

Amir Barak
profile image
Code highlighting ftw!
All my structs have different colors from my classes...

Kujel s
profile image
I may have to tweak my settings in VS to highlight that difference cause on defualt structs and classes are both highlighted blue and it would be handy to see the difference.

MrPhil Ludington
profile image
Can you share any more details or links about the LINQ issue and memory leaks?

Wendelin Reich
profile image
So LINQ introduces (at least) two different sources of memory leaks:
(1) It creates (potentiall many) intermediate collections before returning the final one, all of which are allocated on the heap.
(2) If lets you use true closures (as defined in the article: delegates that bind non-local variables).

I cannot find any detailed articles, but the memory issues with LINQ seem well known among game developers, not just those using Unity. That said, you may still be able to use it safely at startup / level-loading time. Try it out!

http://theinstructionlimit.com/top-sources-of-heap-garbage

http://forum.unity3d.com/threads/140673-Garbage-Collection-Alloca
tions-and-Third-Party-Assets-in-the-Asset-Store/page10

MrPhil Ludington
profile image
Thanks for the reply (and the article!) Did you maybe leave a link out of (2)? I googled "delegates that bind non-local variables" but didn't see anything obvious.

I'm working on a "experiment" to see and will share the results.

Thanks!

Dusty Hunsaker
profile image
So now that Unity 4.3 is shipping with the latest version of MonoDevelop (4.0.1), how does this all change?

MrPhil Ludington
profile image
Nothing changes because MonoDevelop is separate from the internals that Unity uses at runtime, it's just the IDE.

Wendelin Reich
profile image
Haha, yes, I actually had to check that right away. Sadly (though good for me, as the author), nothing changes. Mono is still frozen at 2.6.5, and the C# compiler bug that I mention in the article and the comments is unchanged. Of course, the giveaway should have been that Unity's release notes don't mention any changes to either the Mono libraries or the compiler.

From what I've picked up - but these are just rumours - there seem to be very real reasons for why Unity hasn't updated either component. Copyright issues with parts of Mono could be one aspect of this, technical troubles another.

MrPhil Ludington
profile image
My understanding is cost is a big road block because the new tech in Mono is owned by Xamarin and they want a big licenses fee.

Dusty Hunsaker
profile image
Good to know! Thanks for the insight.

@Justin Pierce: Great minds think alike?

Justin Pierce
profile image
Unity 4.3 includes an updated Monodevelop 4.0.1 -- does that change anything in terms of this article?

edit: hah, beaten by seconds!

Mihai Cozma
profile image
Well, Monodevelop is just an editor, that does not change the custom Mono fork Unity is using. You are still limited to that and to .NET 2.0 (I think, haven't checked the max supported version).

Matthew Mouras
profile image
This is a fantastic article. I'm looking forward to the next in the series. Thanks much!

Troy Walker
profile image
you wouldn't happen to have a wordpress blog I could subscribe too would you?... I don't want to miss your next articles!

Adam Merkel
profile image
Any chances that you'll go into detail about .NET's IDisposable interface? It's more controllable and predictable compared to standard GC, but comes at the cost of losing Windows XP support.

Martin Bell
profile image
It's only more controllable if you manually call Dispose on an object when you're finished with it. Otherwise the GC will pick it up at some later undetermined time (or when you call GC.Collect).

Christopher Myburgh
profile image
The Keys and Values properties on Dictionary use the "lazy initialization" pattern, so they only cause heap allocations the first time that they are called on any given instance.

Wendelin Reich
profile image
Actually, they don't follow that pattern, which you can easily verify yourself. According to the Profiler, the following allocates 12 bytes per call (replace square by angle brackets):

Dictionary[int, int] dictIntegers = new Dictionary[int, int]();

void Update() {
Dictionary[int, int].KeyCollection kc = dictIntegers.Keys;
}

Christopher Myburgh
profile image
How strange. I'm looking at the disassembly in MonoDevelop-Unity (4.3) and it's clearly using lazy initialization... Any idea then why reading the Keys property on the same dictionary instance would still cause an allocation every time? There's no boxing taking place.

Harald Csaszar
profile image
What might be interesting for some as well is that if the single-threaded mono 2.6.5 garbage collector kicks in from another thread it pauses all other threads as well, however leaving no garbage-collector spike in the profiler. Thus we found it helpful to have a "NO_THREADS" compile-flag which would lead to all threaded tasks being executed in the main Unity-thread instead, just to make all memory problems apparent in the profiler.

Matthew Owen
profile image
Great article. I am a longtime C# app dev and have been having a hard time finding info on Unity aimed at programmers as opposed to people who are just starting for the first time.

There are some great tricks for avoiding garbage generation that were developed for use with XNA which are probably still relevant for unity. The XEN framework for XNA in particular has some great code: http://xnaxen.codeplex.com/

I might suggest that in the future articles a distinction is drawn between a "memory leak" and excess garbage generation (or a "garbage leak"). Even in .NET, you can still get proper unmanaged resource leaks (memory, handles etc...) when using objects or methods that make use of unmanaged resources. Anything involving loading or manipulating bitmaps or sound files usually involves unmanaged resources under the hood. And for the simpler garbage collectors it is possible to end up with managed heap not being flagged for collection even when it is no longer usable.

Casey Labine
profile image
> "Value types are allocated on the stack, reference types on the heap."

A common misconception. There are several pieces by ex-MSFTer Eric Lippert worth reading for anyone interested in these details:

http://blogs.msdn.com/b/ericlippert/archive/2009/04/27/the-stack-
is-an-implementation-detail.aspx

http://blogs.msdn.com/b/ericlippert/archive/2009/05/04/the-stack-
is-an-implementation-detail-part-two.aspx

http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-
about-value-types.aspx

Kujel s
profile image
Very interesting read thanks for posting.

Wendelin Reich
profile image
> "A common misconception."

No, not a misconception, but an intentional, widely shared, and useful simplification. A simplification often made in the Microsoft docs.

Eric wants to drive home the point that the distinction is more subtle because he wants C# developers to treat stack vs. heap allocations as a black box. As I mentioned in the article, this is the kind of attitude you often find on places like SO, but it doesn't work in a Unity context.

Amir Barak
profile image
I do have to ask though, why doesn't it work in a Unity context? it still adheres to the C# .Net specifications, no?

Wendelin Reich
profile image
For the reasons described in the article: letting the runtime handle memory management and treating the stack/heap distinction as a black box leads to fps-drops.

There is actually a long-standing debate on the pros and cons of garbage collection. I would love to have the luxury of siding with the 'pro' camp, but it sometimes ignores the fact that games are 'real-time systems' (albeit 'soft' ones). As such, they compete with the GC for CPU time, and I don't think this problem will go away entirely with generational GC.

Evan Combs
profile image
You should be pro GC, just I don't think we are at a point in its development where we can be completely hands off. I think there needs to be given more control over when it is called, and when it isn't called, as well the ability to completely control deallocation if the programmer sees a specific need for it. GC just isn't ready to be on its own when it comes to games, but at the same time it is also a useful tool to make programming quicker and easier. It just needs a little guiding hand from the programmer to act exactly how it is needed.

Erdin Kacan
profile image
Hello,

I have known about the StartCoroutine issue for a while. I have a couple of questions.

Is there any differences between using StartCorutine(Dummy()); or StartCoroutine("Dummy");

Also do you know how is the memory allocation of InvokeRepeating ?

I was considering replacing some of my StartCoroutine calls with InvokeRepeating.

Nuttachai Tipprasert
profile image
According to Unity documentation, the main difference is that with the second one you can use StopCoroutine("Dummy") to stop your coroutine while the first one cannot.

Also, the later one allocates a string object behind the scene, so, it's bad for garbage collecting and should be avoided using inside the loop.

The Invoke* functions are implemented by using reflection. Reflection have very huge overhead when calling and should be avoided. Coroutine, on the other hand, has very little or no overhead (depending on which StartCoroutine version you using), so, it is a better alternative for Invoke*.

Steven Sauer
profile image
Excellent post Mr. Reich. Easy to read, flowed nicely, and great links for additional information. I literally just made an account to give you praise on this. Great work!

I do have a question on Boxing though.

I think I understand the definition, the question is on the (==) equality operator. What I think I saw in the link was someone trying to cause a situation where they could create a quick, fast function to handle the object casting of the double value type. That way it's a single short function that can be allocated and de-allocated quickly, with as little mess in the heap as possible.
The way I'm seeing it, something like "x == y" is a situation that equates to something like "x == (x.GetType())((obj)y)"
If I am at least partially correct (or at least have the right idea) then is there at least some sort of compile time fixes to make sure this doesn't happen with obvious types that are the same? Such as two class members being compared in a functions? Or even a function that takes two of the same type and compares them somewhere in the function?

Pardon me for any silly errors in my post, its rather late.

Aaron Oostdijk
profile image
Good stuff! I've been running into memory problems on iOS a lot with Unity as well, which is mostly down to the fact that our game runs continuously without going to different scenes. I resorted mostly to object pooling and hunting down allocations, although I have some dynamic meshes which update every frame that still allocate some heap. I haven't found a way to prevent that entirely as of yet.

Aside from code optimisations, it can be a good idea to rethink how you get other resources into your game as well. I recently discovered Resources.UnloadAsset works very well (no frame stutter), and is a good alternative to UnloadUnusedAssets or GC.Collect when managing large amounts of AudioClips or Textures without switching scenes.

The only thing I'm still missing is a Resources.LoadStreamed, which doesn't hang your entire game while it's loading. There might be a way to do that through WWW though, but I haven't spent enough time looking into that.

Robert Ling
profile image
Fantastic article, thanks much. I look forward to the next two.

Steven An
profile image
Is it just me or does StringBuilder not even really work when you need alloc-free string formatting? My current solution is to simply reduce how often I format strings - I no longer do them every frame, I do them in response to rare events.

Also, having any active OnGUI and OnMouse* event handlers in your components will cause Unity GUI system to GC alloc like crazy. ^_-

Dmitriy Pyalov
profile image
Good news, everyone :)
There is a Pull Request on Unity's mono repository at Github in order to fix the "foreach" issue.

Wendelin Reich
profile image
Thanks for the hint, looks interesting!

However, if the people at Unity actually go through the trouble of testing and merging Richard Fine's changes, that would really eradicate my hopes that they switch to a newer version of mono any time soon :/

Andreas Siegrist
profile image
They have at least merged the changes: https://github.com/Unity-Technologies/mono/commit/bd2dbed778d2e4d7643df68 cbd4b6fe103a470e2

Let's hope for an update soon

Sohail Shafii
profile image
Great article here...I've learned a lot. Unfortunately I use foreach A LOT, which means I will have to do a significant code refactoring. I don't use another C# compiler besides Unity (on my mac), so I'll just to be careful.

One of the biggest issues with letting go foreach (at least until Unity fixes that bug by adopting a newer version of Mono, maybe in Unity 5) is that it is so suitable for dictionary keys and values. So instead of doing:
foreach (string key in dictionary.Keys)
{
// assumes each key is a string
}
one must do:
for (int i = 0; i < mNeighborGroupControls.Keys.Count; i++)
{
string key = mNeighborGroupControls.Keys[i];
}

I'll probably do a test for myself just to see how things work out. I assume the latter doesn't do any allocations.

Other unfortunate drawbacks of Unity's current version of Mono include heap fragmentation which you referred to (http://answers.unity3d.com/questions/181543/real-memory-isnt-free
d-when-changing-scene-on-ios.html) and also I don't think it returns unclaimed memory after it has been released:

http://forum.unity3d.com/threads/239943-Heap-size-grows-and-never
-returns-memory-to-OS

Sohail Shafii
profile image
Actually...I can't iterate keys like I suggested above. You can ignore that part.


none
 
Comment: