Strings and the garbage collector

I’m trying to optimize my game and every now and then I get a small jerk pausing the game. As the game is a fast jumping game, this can cause a loss of life if it happens in the wrong place.

After looking over the forums, it seems that the garbage collector could be to blame. It also seems that using strings is a bad idea as they are created and destroyed as you use them. Because of this I have removed all strings in the main update and do not add or destroy objects while the game is running. Everything is pre-loaded at start to stop this sort of behavior.

My first question is simply, dose the animation.Play command create and destroy a string causing the garbage collector to clean up latter? i.e. animation.Play(“Jump”);

I also have a score that updates as the game is playing. It’s a gui text object and the only way to update is a string.

paddedScore = ScoreInt.ToString(“00000#”);
ScoreObject.guiText.text = (ScoreText + paddedScore);

Is this the cause of the jerk every now and then?

lastly, is there anyway to control when or how often the garbage collector comes along?

Thanks,

Richard

This links to the creator of Zombieville USA talking about this issue. It should give you what you need to know.

http://forum.unity3d.com/threads/20786-AnimationStates-allocate-piles-of-memory?p=141108#post141108

Garbage collection may not be the culprit, Unity’s GC behavior has improved greatly in more recent versions and what you might be reading on the forums could be out of date. For starters, GC no longer runs after 4mb of junk accumulate, it runs far sooner now. So if your code is allocating a lot of stuff every frame, you’ll have more frequent, but less severe GC-related hiccups than you might have in past versions of Unity. The best way to be sure is to run the internal profiler and keep an eye peeled for it - it will tell you not only when garbage collection occurs, but the exact amount of milliseconds it took to perform.

Strings are fine to use and will only cause repeated, needless allocations if you’re concatenating them excessively, like say… every frame. The way you’re forming your GUIText string is allocating memory, but it’s probably fine to do that as long as you only perform that operation when the score actually changes. If you’re just letting it re-create that string every frame, that’s probably hundreds of times more often than is necessary and will eventually lead to GC running, possibly after mere minutes of play.

Thanks for the replies.

Billamu, thats the sort of posting I was reading before, hence the string questions.

MikaMobile, It’s good to know the garbage collector has been improved, I did noticed a big speed difference and less pauses when I upgraded from 1.7 to 3. Unfortunately that score code is run every frame. My games score is based off the X movement of the main character who is always running forward. It’s a jump and duck game (It’s actually a iphone version of Jurassic Omelet in my link below). From that I guess the score is the problem as I have seen a lot less pauses since optimizing everything else.
I also saw a improvement by lowering the “Maximum Allowed Timestep” to 0.05. The docs mentioned this will smooth out garbage collection. They also say it’s recommended to not drop below 1/10th a second, which I’ve done and seems to work fine on the iphones I’ve tested on (3G 8 gig and above).

I guess now my only question is about the score. Is there a better way to turn a int into a string and pass it to a guiText object without allocating memory each frame?

Thanks,

Richard

Hmm, there are lots of ways to build a scoreboard-type thing that doesn’t involve strings or gui at all. You could have a bunch of polygons with a texture atlas that looked like this…

1 2 3 4 5 6 7 8 9 0

… parse the score int and figure out how to set the UV’s of each of those polygons to the right part of the texture to display the correct digit. I did something like this for the “money” readout in zombieville, although I used a semi-elaborate skinned mesh rather than dynamically changing UV’s in order to keep the draw calls down.

But before going crazy with a complicated solution, I’d of course try disabling your score code temporarily and see if it alone is the cause of your hitches.

EDIT: actually, you probably don’t need anything that complicated, the culprit is concatenating ScoreText and your int. Maybe just make the score text a separate gui element that’s just positioned where it needs to be?

1 Like

Thanks a lot for the help MikaMobile. It seems I’ve managed to fix the problem by using String.Format instead, which eliminated one of the strings, but the main fix was to change how I score. Instead of it going up each frame based on the distance moved, I’ve switched it to a timer so it now increments by 10 every quarter second. The end result is about the same score wise, but it’s a lot less to handle in the update loop.

I like the idea of skinned meshes for the GUI. I’m much more comfortable in Maya which would open up a lot of GUI effects and animation. Thanks for the tip.

I do have one more question for anyone reading this thread. I’ve seen a few other posts about jerky updates which all seem to be garbage releated. Is this just a java problem or does C# allow you to free up your own resources? I’m just wondering if this problem is less if I switched to C# for my next project.

Thanks,

Richard

Here’s what the Unity Ref Manual for Unity Iphone says about GC. Hope it helps:

Optimizing Garbage Collection

As mentioned above try avoiding any allocations
If allocations can’t be avoided then there are two allocation/collection strategies :

  • small heap fast and frequent garbage collection

This strategy might work well for games that have long action gameplay and needs smooth framerate.
Typical heap for Unity iPhone game which allocates small blocks for short period of time often is ~200 KB, garbage collection of such heap takes ~5ms (on iPhone 3G). With a 1 MB heap the duration of garbage collection increases to ~7 ms.
Sometimes it can be useful to force garbage collection every Nth frame:

if (Time.frameCount % 30 == 0)
{
   System.GC.Collect();
}

But use it with care, watch internal profiler statistics and make decisions based on them.

  • large heap slow and rare garbage collection

This strategy might work for games that are have short to medium length smooth framerate demanding gameplay. The idea is to avoid garbage collection while gameplay is running and make garbage collections during gameplay pauses. It is good idea to preallocate some space on the heap during startup which is large enough to survive gameplay sessions yet small enough to avoid application killing by OS because of low system memory. Mono tries to expand the heap only when necessary, so sometimes it is good idea to force its expansion on startup:

function Start() {
	var tmp = new System.Object[1024];
	// make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks
        for (var i : int = 0; i < 1024; i++)
		tmp[i] = new byte[1024];
	// release reference
        tmp = null;
}

Later you can force garbage collection when gameplay is paused:

System.GC.Collect();

Use this with care, pay attention to internal profiler statistics and make decisions based on the actual numbers.

So, I guess you could free up resources to a certain extent (by designing when and how you would call GC).

Thanks a lot for the info. I can’t believe I missed that in the docs. I was spending too much time looking on the forum for posts about strings and memory allocation. I have a few places I can use this to help even more.

Thanks,

Richard

I just wanted to update this post for anyone else who is looking into frame dropping problems. After the great advice received here, I managed to get my game running a lot better, however, there where still a few times when it dropped frames. Last night I managed to get the game to run smoothly with no frame dropping at all by switching my background music to decompress on load and turning off the hardware decoding. I would have thought this would slow things down, but it seems to have fixed all my problems.

Thanks,

Richard

I believe making the string literals as constants will also aid in performance enhancement since constants are treated differently by compilers for decreasing the execution time

object is object, the const string just isn’t garbaged but thats about it.
The most important thing to do is:

  1. Don’t use tags unless unavoidable
  2. Don’t do string comparisions, no matter what excuse you have, even after a decade I’ve yet to see a single thing that you can’t compare through ints / enums!
  3. Don’t use string + string for longer chains, use String.Format instead as + generates a new string each time which can skyrocket it
1 Like

On 1. Does this mean not tagging objects at all or just not using the tag to “Find” them or refer to them?

On 3. If I have to change a score int to a string to show it in EZGUI will this as well generate a new string every time using timePassed.ToString() for example? Because it seems to me that this is the same as a new string each uptick on the timer.

Best
BTH

  1. You could use layers ( Unity - Manual: Layers and Unity - Scripting API: GameObject.layer ) since during comparison it is cheaper to compare integers instead of strings. This is useful in collisions. Regarding finding an object I think that by instancing prefabs and keeping a reference at them as shown here http://forum.unity3d.com/threads/76637-any-method-of-referincing-to-a-specific-prefab-after-instantiated-and-during-the-gam is cheaper than using Find. Specifically, calling them via

myPrefabArray*.DoYouStuff();*

Sorry for the necro-post, but Google Now just brought me to this thread, and I though I’d weigh in. I wrote a blog post a while back about my recipe for garbage-free string manipulation. It might be of use: