您发布的信息不足以为您提供有根据的猜测。这是我有根据的猜测:
如果你在 Draw 方法中做这样的事情:
spriteBatch.DrawString(font, "Score: " + score, location, Color.Black);
spriteBatch.DrawString(font, "Something else: " + foo, overHere, Color.Black);
spriteBatch.DrawString(font, "And also: " + bar, overThere, Color.Black);
然后,每个调用都会在每次运行时在您背后创建新的 string 和 StringBuilder 对象。因为它们在您的 Draw 方法中,所以每个可能每秒运行 60 次。那是分配了很多临时对象!
要验证是否是这种情况 - 使用 CLR Profiler。听起来你已经这样做了。
虽然这并不是真正的“泄漏”——垃圾收集器最终会清理它们——但这种分配模式在游戏中是不可取的。请参阅this blog post,了解游戏中处理垃圾收集的两种方法。方法 1 通常更容易并且提供更好的结果 - 所以我在这里讨论它。
此时值得一提的是,PC 上的 GC 速度足够快,这样的分配并不重要。 GC 会以很少的开销清理微小的对象(例如您的临时字符串)。
另一方面,在 Xbox 360 上,即使像这样定期产生少量垃圾也会导致一些严重的性能问题。 (我不确定 WP7,但我个人会像对待 Xbox 一样对待它——小心!)
我们如何解决这个问题?
答案很简单:DrawString 将接受StringBuilder 的实例来代替string。创建StringBuilder 的一个实例,然后在每次需要组合自定义字符串时重用它。
请注意,将数字或其他对象隐式或通过其ToString() 方法转换为字符串也会导致分配。因此,您可能必须编写自己的自定义代码以附加到 StringBuilder 而不会导致分配。
这是我使用的一种扩展方法,用于在不分配的情况下将整数附加到字符串:
public static class StringBuilderExtensions
{
// 11 characters will fit -4294967296
static char[] numberBuffer = new char[11];
/// <summary>Append an integer without generating any garbage.</summary>
public static StringBuilder AppendNumber(this StringBuilder sb, Int32 number)
{
bool negative = (number < 0);
if(negative)
number = -number;
int i = numberBuffer.Length;
do
{
numberBuffer[--i] = (char)('0' + (number % 10));
number /= 10;
}
while(number > 0);
if(negative)
numberBuffer[--i] = '-';
sb.Append(numberBuffer, i, numberBuffer.Length - i);
return sb;
}
}