这是我在此的头一篇博文。 我在Visual Studio 2010中做一个游戏使用XNA,我已经打了一个巨大的内存泄漏。 我的游戏开始了用17K RAM中,然后十几分钟后它高达65K。 我跑了一些内存分析器,他们都说正在创建的String对象的新实例,但他们没有生活。 字符串的活动实例的数量都没有改变。 它也创造字符的情况下,[](这是我想从它期望的),对象[],和StringBuilder的。 我的游戏是相当新的,但有太多的代码张贴在这里。 我不知道如何摆脱那些不住实例,请帮忙!
Answer 1:
您还没有公布足够的信息,为您提供比猜测更。 这是我的猜测:
如果你正在做你的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探查。 这听起来像你已经做到了这一点。
虽然这不是一个真正的“泄漏” - 垃圾收集器将最终清理它们 - 这种分配模式是在游戏不可取的。 见这个博客帖子大约两个方法来与垃圾收集游戏中的交易。 方法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;
}
}
Answer 2:
有在C#中没有内存泄漏(或不好,他们很难得到)。 你遇到的是正常的。 垃圾收集器并不“感觉”像它需要收集的内存,所以也没有。 当内存不足,就会发生垃圾收集。 如果你是绝对肯定的,你不守不需要引用您的string
s,则一切都很好。
如果你想强制GC循环使用GC.Collect()