Tuesday, November 22, 2011

Unity3D GC Spikes

If you've been working with Unity3D for a while, you've probably noticed when the garbage collector kicks in, your frame rate suffers, very badly. I've spent some considerable time trying to eliminate these hiccups from my AI code, with no success. I ended up reducing the problem to a simple project which loads and runs 1000 coroutines forever, which do nothing except yield 0. This is the result in my profiler.



Those nasty spikes are where the GC kicks in and performance plummets. It's particularly nasty on iOS. The question is, how to fix? I have no idea. This project only runs coroutines which do nothing. No allocations, instantiations or anything else. Yet, the GC still kicks in very frequently. Too frequently. If _anyone_ has a solution for this, I'd love to hear it. I'm worried the problem is too fundamental to Unity3D to fix in any way... Try for yourself if you like. spiker.unitypackage Update: After running this same test and profiling the iOS and Desktop builds, the GC spikes disappear completely. The less I have learnt, is don't rely on profiling in the Editor!

9 comments:

ratking said...

I once had pretty annoying hiccups in a game which used some external pathfinding script with GUI. The thing is, the GC hiccups mainly came from the editor functionality of the pathfinding tool - after hours of trying to find the problem I deployed the project just to see that it worked flawlessly as an executable. I could then identify the culprit.
So, can you rule out the fact that the problem with the GC collecting the garbage only exists in the editor? Just a thought ...

Anonymous said...

it seems that the result of your test is that coroutines generate shedloads of garbage :).

i dont know why you are testing with "1000 coroutines". maybe u can avoid coroutines completely. in my medium sized project the only time we use coroutines is for some async loading of assetbundles - no where else.

lucas meijer said...

Which version of Unity is this?
Are you profiling in the editor, or the iOS game?

I tried to reproduce with your project on an internal unity3.5 build, and didn't manage to get GC.Collect() to show up even once in the profiler. (I was profiling the content in the editor itself).

Your coroutine code looks very light on gc pressure, since the thing it yields is just a number and not a new instance of say WaitForSeconds.

Simon Wittber said...

@Anonymous
Coroutines are incredibly useful for maintaining state through multiple frames. You're missing out if you're not using them! In our current project (20000 loc) we have a total of 104 coroutines.

Simon Wittber said...

@Lucas
Version is Unity 3.4.2f3. The fact that it doesn't happen in 3.5 is excellent news! The graph is from an editor profile session. I'll do an iOS session and post results.

Anonymous said...

yeah i should jump on the yield bandwagon. if they dont generate shedloads of garbage :). which im fairly sure they wouldnt, noone would use otherwise. be sure to post what was generating all the garbage when you find out.

Anonymous said...

actually, foreach loops generate IEnumerator-related garbage (i dont remember the exact details). perhaps coroutines generate similar garbage for the same reasons which is normally acceptible but you are using too many off them. i have no idea, just a random thought.

Anonymous said...

If you plan on running lots of coroutines, use
yield return null;
instead of
yield return 0;

Difference: 0 first has to be implicitly casted to IEnumerator and then be identified as to actually mean null, which is definitely overhead you can avoid.

Anonymous said...

Any luck with your garbage woes?

Popular Posts