2011-09-08 55 views
10

我正在开发Windows Phone 7 XNA游戏。这是用C++编写的游戏的一个端口,因此,我尽可能少地重写游戏代码。WP7中的可变字符串C#/ XNA?

垃圾是巨大问题在WP7上,因为收集器是非代和慢的,所以一个集合(每1MB触发一次)每MB分配大约需要10ms。我完全打算使用最大90MB的可用空间,因此我们正在寻找每MB分配约900毫秒的失速。

我已经能够重写的东西,使我们没有垃圾产生的每帧,除了少数情况下的字符串。

看来StringBuilder.ToString()会生成垃圾,并且描述的方法here在WP7上不起作用。

的两件事情我需要做的是:

  • 格式分/秒/ hundreths为毫米:用于显示屏幕ss.hh。显然,我可以用StringBuilder来做到这一点(使用扩展方法,不会从装箱内容中创建垃圾),并直接使用SpriteBatch显示StringBuilder。
  • 将形式为“foo.bar.baz.qux”的字符串拆分为'。'即{“foo”,“bar”,“baz”,“qux”}中的一个数组,并将一个元素复制到时间转换为字符串数组。这是为了设置游戏角色的等级状态。它也非常直接地从原始游戏移植过来,并且相当一部分依赖于它以这种方式工作。我真的很想避免重写它。

缺乏将大量代码转换为使用char []而不是字符串,有没有什么办法在C#中有真正的无垃圾可变字符串?

+2

只是一个侧面说明芒果有Generational GC http://blogs.msdn.com/b/abhinaba/archive/2011/04/13/generational-gc-in-windows-phone-mango.aspx – Terrance

+0

此外,这是一种使某些东西“更接近”可变字符串的方法http://stackoverflow.com/questions/6913435/how-to-get-a-list-of-mutable-strings – Terrance

回答

10

为什么您需要首先将StringBuilder转换为String?如您所知,您可以直接将StringBuilder传递给XNA的绘图方法。您还可以使用StringBuilder检索子:

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

要避免与 StringBuilderToString()AppendFormat()唯一的东西。其他格式化方法(据我所知)都没有产生垃圾。 更新:我错了。编写你自己的扩展方法。可以在这里找到一个简明的例子:Avoiding garbage when working with StringBuilder

编写一个方法会比较容易,它会根据给定的分隔符将字符串拆分为子字符串。请记住,String.Split()是邪恶的两个的原因 - 首先,因为它分配新的字符串;第二,因为它分配一个新的阵列。字符串的不变性只是你问题的一半。

请考虑以下扩展方法StringBuilder。我没有彻底测试过这个代码,但它应该给你一个大概的想法。请注意,它期望您传入预先分配的数组,然后它将填充。

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; 
} 
+1

格式化非字符串对象(例如:数字)将生成垃圾(它调用他们的'ToString'方法)。但是为附加整数(或其他大多数类型)编写一个无垃圾扩展方法非常简单。你可以在网上很容易找到例子。 –

+0

快速浏览经反编译的源代码,确认您是正确的。我不确定我为什么会这么想。但是,是的,你可以解决这个问题。 –

0

我想要做的游戏性代码尽可能少重写。

小心,重写可能需要更长的时间。科尔坎贝尔是正确的,当你想要绘制它时没有必要调用ToString()。 XNA的绘制方法采用了StringBuldier,在我的游戏中效果很好。

解决您问题的另一种方法:为您的字符串创建全局HashSet,并在加载游戏或关卡时设置它以避免收集压力。

尝试尽可能地加载游戏时尽可能多地做。