C#/ XNA巨型内存泄漏

这是我在此的头一篇博文。 我正在使用XNA在Visual Studio 2010中制作游戏,而且我遇到了巨大的内存泄漏。 我的游戏开始使用17k ram,然后在十分钟之后达到65k。 我运行了一些内存分析器,他们都说正在创建String对象的新实例,但它们不是实时的。 String的实时实例数量根本没有变化。 它还创建了Char [](我期望它),Object []和StringBuilder的实例。 我的游戏很新,但是在这里发布的代码太多了。 我不知道如何摆脱不活的实例,请帮忙!

您还没有发布足够的信息来为您提供更多有根据的猜测。 这是我受过教育的猜测:

如果你在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); 

然后每次调用都会在每次运行时在后面创建新的stringStringBuilder对象。 因为它们在你的Draw方法中,每个可能每秒运行60次。 这是很多临时对象被分配!

要validation是否是这种情况,请使用CLR Profiler。 听起来你已经做到了这一点。

虽然这不是真正的“泄漏” – 垃圾收集器最终将清理它们 – 这种分配模式在游戏中是不可取的。 请参阅此博客文章,了解有关处理游戏中垃圾收集的两种方法。 方法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]; /// Append an integer without generating any garbage. 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; } } 

C#中没有内存泄漏(或者,它们很难获得)。 你正在经历的是正常的。 垃圾收集器不“感觉”它需要收集内存,所以它没有。 每当内存不足时,就会发生垃圾回收。 如果你完全确定你没有保留不需要的string引用,那么一切都很好。

如果要强制GC循环,请使用GC.Collect()