3

これは私の最初の投稿です。XNA を使用して Visual Studio 2010 でゲームを作成していますが、巨大なメモリ リークが発生しました。私のゲームは 17k RAM を使用して開始し、10 分後には最大 65k になります。いくつかのメモリ プロファイラーを実行しましたが、すべて String オブジェクトの新しいインスタンスが作成されているとのことですが、それらは有効ではありません。String のライブ インスタンスの量はまったく変わっていません。また、Char[] (私が期待する)、Object[]、および StringBuilder のインスタンスも作成しています。私のゲームはかなり新しいですが、ここに投稿するにはコードが多すぎます。ライブではないインスタンスを削除する方法がわかりません。助けてください!

4

2 に答える 2

5

知識に基づく推測以上のものを提供するのに十分な情報を投稿していません。これが私の経験に基づいた推測です:

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メソッド内にあるため、それぞれが 1 秒あたり 60 回実行されている可能性があります。これは、多くの一時オブジェクトが割り当てられていることです!

これが事実であることを確認するには、CLR プロファイラーを使用します。あなたはすでにこれを行っているようです。

これは実際には「リーク」ではありませんが (ガベージ コレクターは最終的にそれらをクリーンアップします)、この割り当てパターンはゲームでは望ましくありません。ゲームでガベージ コレクションを処理する 2 つの方法については、このブログ投稿を参照してください。通常、方法 1 の方が簡単で、より良い結果が得られるため、ここで説明します。

この時点で、PC の GC は十分に高速であるため、このような割り当ては問題にならないことに注意してください。GC は、ごくわずかなオーバーヘッドで小さなオブジェクト (一時的な文字列など) をクリーンアップします。

一方、Xbox 360 では、このように少量のガベージを定期的に生成するだけでも、深刻なパフォーマンスの問題を引き起こす可能性があります。(WP7についてはよくわかりませんが、個人的にはXboxのように扱います-注意してください!)

どうすればこれを修正できますか?

答えは簡単です:の代わりに のDrawStringインスタンスを受け入れます。のインスタンスを 1 つ作成し、カスタム文字列をまとめる必要があるたびにそれを再利用します。StringBuilderstringStringBuilder

暗黙的に、またはそのメソッドによって、数値またはその他のオブジェクトを文字列に変換すると、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;
    }
}
于 2012-06-07T02:01:40.170 に答える
2

C#にはメモリリークはありません(または、取得するのが非常に困難です)。あなたが経験していることは正常です。ガベージコレクターは、メモリを収集する必要があると「感じ」ないため、そうではありません。メモリが不足すると、ガベージコレクションが発生します。自分のsへの不要な参照を保持していないことが絶対に確実な場合は、すべて問題ありません。string

GCサイクルを強制する場合は、を使用しますGC.Collect()

于 2012-06-06T22:36:19.023 に答える