C#/ XNA巨内存泄漏(C#/XNA Giant Memory Leak)

2019-07-29 18:26发布

这是我在此的头一篇博文。 我在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);

然后,每个这些电话的将创建新的stringStringBuilder每次运行时你背后的对象。 因为他们是在你的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()



文章来源: C#/XNA Giant Memory Leak