Consider following example. I have a title screen for a game which displays top scores list, and some other text. The Update method looks like (simplified):

// remove all text

// add scores
foreach(var sc in scores)
    textList.Add(new GameText(string.Format("{0}: {1}", sc.Name, sc.Score));

If I understand all correctly, then each frame 10 new strings are created, polluting memory at high rate. Currently I fight it with creating a cache:

// this is a class level variable, outside of Update method of course
List<GameText> scoreCache = new List<GameText>();

// remove all text

// add scores to cache if needed
if(scoreCache.Count == 0)
    foreach(var sc in scores)
        scoreCache.Add(new GameText(string.Format("{0}: {1}", sc.Name, sc.Score));

// get fast copy from cache 
// no new strings created until score cache is invalidated

I wonder, if there are some other reliable solutions and patterns to this common, as I see it, problem?

Update. As @JasonH correctly mentioned, there is no need to update list each time at all, so now scoreCache is initialized once in a LoadContent-like method which is called once before main Game loop starts.

Update 2. Another similar problem was with a debug text layer output which displays FPS, Total game time, etc. on top of all screens. Despite using StringBuilder, intermediate strings were required for creation of final debug text for each frame. I've decided to solve it this way, since I don't actually need per frame response, I update this only each second:

private void PrepareDebugText(GameTime gameTime)
    this.refreshAccumulator += gameTime.ElapsedGameTime.TotalMilliseconds;

    // if required time is not elapsed yet
    if (this.refreshAccumulator < RefreshIntervalMs)
        // do nothing

    // reset accumulator
    this.refreshAccumulator = 0;

    // create debug text below
    // ...

Applying this two approaches gives following:

  • reduced garbage collection frequency by 2 (from 60-70 seconds to 130-140 seconds)
  • reduced peak heap allocation from 3,4 Mb to 1,5 Mb
  • reduced short life objects to less than 1% from more than 50%.

Now I'm satisfied.

Update 3. @GeorgeDuckett found an interesting approach example how we can further reduce string pollution then output is integer number.

I also would like to clarify why strings are so specific in XNA (.NET). Despite being a reference type, on each assign (i.e. =) operation new string is created instead of assigning reference. This can produce not very obvious amounts of garbage strings.

  • 5
    \$\begingroup\$ Do you really have a problem with this? When you are displaying the top scores list you are in a non critical section of your game... the garbage collector will work without causing problems... you should worry when you have a real problem.... not now \$\endgroup\$
    – Blau
    Apr 18, 2012 at 8:24
  • \$\begingroup\$ Personally I think caching to memory, as you have done in the second example, is probably more suited. However, is there a reason why you are clearing and re-adding the collection each Update cycle? Wouldn't it be more appropriate to just invoke this process once when the high score is displayed? \$\endgroup\$
    – Jason H
    Apr 18, 2012 at 9:33
  • \$\begingroup\$ @Blau: In his example it's probably ok, but in the more general case it would be useful to see other's approaches. \$\endgroup\$ Apr 18, 2012 at 9:38
  • \$\begingroup\$ @Blau you are right, but this doesn't make this situation normal. Usually I start to worry then I see potential problem. This is one. This also usually indicate that I'm doing something not in the right way. \$\endgroup\$
    – pabdulin
    Apr 18, 2012 at 10:21
  • \$\begingroup\$ @JasonH you are absolutely right, just realized that not long before you comment. High scores are now read once at LoadContent-like method. \$\endgroup\$
    – pabdulin
    Apr 18, 2012 at 10:23

2 Answers 2


So here is general tips:

  1. Don't create static (i.e. which doesn't change) strings in Update, create then in Initialize or LoadContent.

  2. If string is changed occasionally then cache it, and invalidate cache on text change.

  3. Finally, try to reduce string update rate if applicable. For example if you displaying game time with seconds precision, there is no need to update it more frequently then once in a second (this reduces string creation rate by your FPS value).

  4. Suggested by @GeorgeDuckett use StringBuilder optimized routines for displaying integer numbers. My implementation can be seen here.


Generally, what you want to do is create an object pool. It is like your buffer, but managed.

In practice, you would create the pool with a set number of objects; instead of throwing the object out when you are done, you set it to "inactive" and give it back to the pool. When you need to create a new object, just ask the pool for one. It will give you an inactive one and set it's state to active for you.

Keep in mind that you want to carefully tune your pool to contain just enough objects. Pretend you give it 10,000 strings. The GC is going to have to iterate over all 10,000 to see if any are not referenced.* Being that they all will be, it will have been wasted GC time. The best thing is to tune it to just what you need.

See a good implementation of a generic pool here, and you can look at his implementation of an interpolator on how to use it. Let me know if you have any questions.

* There are exceptions. I think if you use an array to hold them then it is a bit different. Don't quote me on that though

  • \$\begingroup\$ Note that since strings are immutable (in C#) an object pool containing them would need to be specialised (if useful at all). Typically you'd put mutable objects in the pool - objects that could have properties reset / changed / re-initialised. \$\endgroup\$ Apr 19, 2012 at 7:03
  • \$\begingroup\$ My initial cache example is similar to Pool, except it's much more basic pattern. The problem is (with Debug layer output) is that I don't know content of the string, thus no reason to put them in Pool. \$\endgroup\$
    – pabdulin
    Apr 19, 2012 at 7:52
  • \$\begingroup\$ @george duckett, yes great point. Thank you for pointing that out. \$\endgroup\$
    – user159
    Apr 19, 2012 at 14:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .