我正在开发Windows Phone 7 XNA游戏。它是用C ++编写的游戏的一个端口,因此,我试图尽可能少地重写游戏代码。
垃圾是WP7上的一个巨大的问题,因为收集器是非代数且速度慢的,所以一个集合(每1MB触发一次)每MB分配大约需要10毫秒。我完全打算使用最大可用的90MB,所以我们每隔MB分配一个~900ms的停止。
我已经能够重做工作,所以我们没有每帧生成垃圾,除了一些字符串的情况。
似乎StringBuilder.ToString()生成了垃圾,而here描述的方法在WP7上不起作用。
我需要做的两件事是:
没有将大量代码转换为使用char []而不是字符串,有没有办法在C#中拥有真正无垃圾的可变字符串?
答案 0 :(得分:10)
为什么首先需要将StringBuilder
转换为String
?如您所知,您可以将StringBuilder
直接传递给XNA的绘图方法。您还可以使用StringBuilder
来检索子字符串:
substringBuilder.Length = 0;
for (int i = start; i <= end; i++)
substringBuilder.Append(originalBuilder[i]);
更新:我错了。编写自己的扩展方法。此处提供了一个简介:Avoiding garbage when working with StringBuilder StringBuilder
ToString()
和AppendFormat()
唯一要避免的事情。没有其他格式化方法(据我所知)生成垃圾。
编写一个将字符串拆分为基于给定分隔符的子字符串的方法相对容易。请记住,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 :(得分:0)
我试图尽可能少地重写游戏代码。
小心,重写可能需要更长时间。 Cole Campbell是对的,在你想要绘制ToString()时没有任何意义。 XNA有draw方法,它采用StringBuldier,在我的游戏中运行良好。
您问题的另一个解决方案:创建字符串的全局HashSet并在加载游戏或级别时设置它以避免收集压力。
加载游戏时尽量做到尽可能多。