9

以下のコードを検討してください。

using System;

namespace memoryEater
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.WriteLine("alloc 1");
            var big1 = new BigObject();

            Console.WriteLine("alloc 2");
            var big2 = new BigObject();

            Console.WriteLine("null 1");
            big1 = null;

            //GC.Collect();

            Console.WriteLine("alloc3");
            big1 = new BigObject();

            Console.WriteLine("done");
            Console.Read();
        }
    }

    public class BigObject
    {
        private const uint OneMeg = 1024 * 1024;
        private static int _idCnt;
        private readonly int _myId;
        private byte[][] _bigArray;

        public BigObject()
        {
            _myId = _idCnt++;
            Console.WriteLine("BigObject {0} creating... ", _myId);

            _bigArray = new byte[700][];

            for (int i = 0; i < 700; i++)
            {
                _bigArray[i] = new byte[OneMeg];
            }

            for (int j = 0; j < 700; j++)
            {
                for (int i = 0; i < OneMeg; i++)
                {
                    _bigArray[j][i] = (byte)i;
                }
            }
            Console.WriteLine("done");
        }

        ~BigObject()
        {
            Console.WriteLine("BigObject {0} finalised", _myId);
        }
    }
}

コンストラクターで 700MiB 配列を作成するクラス BigObject があり、コンソールに出力する以外に何もしない finalize メソッドがあります。Main では、これらのオブジェクトを 2 つ作成し、1 つを解放してから、3 つ目を作成します。

これが 32 ビット用にコンパイルされている場合 (メモリーを 2 GB に制限するため)、3 番目の BigObject の作成時にメモリー不足の例外がスローされます。これは、メモリが 3 回目に要求されたときに要求を満たすことができず、ガベージ コレクタが実行されるためです。ただし、収集の準備ができている最初の BigObject にはファイナライザー メソッドがあるため、収集される代わりにファイナライズ キューに配置され、ファイナライズされます。その後、ガベージ コレクターが停止し、例外がスローされます。ただし、GC.Collect への呼び出しがコメント化されていない場合、または finalize メソッドが削除されている場合、コードは正常に実行されます。

私の質問は、ガベージ コレクターがメモリの要求を満たすためにできる限りのことをしないのはなぜですか? 2 回実行した場合 (1 回はファイナライズ、2 回目は解放)、上記のコードは正常に動作します。ガベージ コレクターは、例外をスローする前にメモリを解放できなくなるまでファイナライズと収集を続けるべきではありませんか? また、このように動作するように構成する方法はありますか (コードまたは Visual Studio を介して)。

4

2 に答える 2

2

GC がいつ機能し、メモリを再利用しようとするかは不確定です。

の後にこの行を追加すると、big1 = null. ただし、GC に収集を強制する場合は注意が必要です。自分が何をしているのかわからない限り、お勧めしません。

GC.Collect();
GC.WaitForPendingFinalizers();

C# でガベージ コレクションを強制するためのベスト プラクティス

GC.SuppressFinalize() はいつ使用する必要がありますか?

.NET のガベージ コレクション (ジェネレーション)

于 2013-02-06T08:22:14.747 に答える
0

ガベージコレクション中にファイナライザーが実行される時間が定義されていないためだと思います。リソースが特定の時間に解放されることは保証されません(CloseメソッドまたはDisposeメソッドを呼び出さない限り)。また、ファイナライザーが実行される順序はランダムであるため、オブジェクトが待機している間、別のオブジェクトのファイナライザーを待機させることができます。 。

于 2013-02-06T08:15:04.907 に答える