简体   繁体   中英

Mutable strings in WP7 C#/XNA?

I'm working on a Windows Phone 7 XNA game. It's a port of a game written in C++, and as such, I'm trying to do as little rewriting of gameplay code as possible.

Garbage is a huge problem on WP7, because the collector is nongenerational and slow, so a collection (which is triggered every 1MB) takes about 10ms per MB of allocations. I fully intend to be using the maximum 90MB available, so we're looking at a ~900ms stall every MB of allocation.

I've been able to rework things so that we don't have garbage generated per-frame, except for a few cases of strings.

It seems that StringBuilder.ToString() generates garbage, and the method described here doesn't work on WP7.

The two things I need to do are:

  • Format minutes/seconds/hundreths as mm:ss.hh for display to the screen. Apparently I can do that with a StringBuilder (using extension methods that don't create garbage from boxing the ints) and display the StringBuilder directly with SpriteBatch.
  • Split a string of the form "foo.bar.baz.qux" into an array on '.', ie {"foo", "bar", "baz", "qux"} and copy one element at a time into an array of strings. This is for setting the hierarchical state of game actors. It's also pretty much directly ported from the original game, and quite a bit depends on it working this way. I'd really like to avoid rewriting it.

Short of converting a lot of code to use char[] instead of string, is there any way to have truly garbage-free mutable strings in C#?

Why do you need to convert a StringBuilder to a String in the first place? As you've noted, you can pass StringBuilder directly into XNA's drawing methods. You can also use StringBuilder to retrieve substrings:

substringBuilder.Length = 0;
for (int i = start; i <= end; i++)
    substringBuilder.Append(originalBuilder[i]);

The only things you want to avoid with StringBuilder are ToString() and AppendFormat() . None of the other formatting methods (to my knowledge) generate garbage. Update: I was wrong. Write your own extension methods. A rundown is available here: Avoiding garbage when working with StringBuilder

It's relatively easy to write a method that will split a string into substrings based on a given delimiter. Just remember that String.Split() is evil for two reasons -- first, because it allocates new strings; and second, because it allocates a new array . The immutability of strings is only half of your problem.

Consider the following extension methods for StringBuilder . I haven't thoroughly tested this code, but it should give you a general idea. Note that it expects you to pass in a pre-allocated array, which it will then populate.

public static void Substring(this StringBuilder source, Int32 start, Int32 count, StringBuilder output)
{
    output.Length = 0;
    for (int i = start; i < start + count; i++)
    {
        output.Append(source[i]);
    }
}

public static int Split(this StringBuilder source, Char delimiter, StringBuilder[] output)
{
    var substringCount = 0;
    var substringStart = 0;
    for (int i = 0; i < source.Length; i++)
    {
        if (source[i] == delimiter)
        {
            source.Substring(substringStart, i - substringStart, output[substringCount]);
            substringCount++;
            substringStart = i + 1;
        }
    }
    if (substringStart < source.Length - 1)
    {
        source.Substring(substringStart, source.Length - substringStart, output[substringCount]);
        substringCount++;
    }
    return substringCount;
}

I'm trying to do as little rewriting of gameplay code as possible.

Careful with that it may take longer that rewrite. Cole Campbell is right, there is no point in calling ToString() while you want to draw it. XNA has draw method that takes StringBuldier and it works well in my game.

Another solution to your problem: make a global HashSet of your strings and set up it when you load the game or level to avoid collection pressure.

Try to do as much as possible when you load the game.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM