2

次のコードが与えられます:

namespace GcDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var list = new List<object>();
            Console.WriteLine("list is in {0} generation.", GC.GetGeneration(list));
            GC.Collect();
            Console.WriteLine("list is in {0} generation.", GC.GetGeneration(list));
            GC.Collect();
            list.Add(new object());
            Console.WriteLine("list is in {0} generation. object is in {1} generation.", GC.GetGeneration(list), GC.GetGeneration(list[0]));
            GC.Collect(0);
            Console.WriteLine("list is in {0} generation. object is in {1} generation.", GC.GetGeneration(list), GC.GetGeneration(list[0]));

        }
    }
}

リストオブジェクトは第2世代にありますが、第0世代にある唯一の参照list [0]オブジェクトです。GC.Collect(0)に収集しないことがどうしてわかるのでしょうか。

4

3 に答える 3

2

この記事には、それがどのように機能するかについての簡単な説明があります。「世代を書き込みバリアで機能させる」セクションをお読みください。これは、テクニックをより詳細に説明するもう1つの優れたブログ投稿です。

エグゼクティブサマリーは、CLRがコードを発行するため、Gen2オブジェクトがいつ書き込まれたかを検出できます。Gen0コレクションを実行するときに検査するデータ構造(「カードテーブル」)への書き込みを記録します。これにより、メモリ内のすべてのオブジェクトをウォークするための全費用をかけずに、Gen2->Gen0参照を見つけることができます。

于 2012-10-10T00:38:56.663 に答える
1

私は正しいですか、あなたの質問は、なぜGCが収集しないのlist[0]ですか?

もしそうなら、答えは、list内部に作成されたオブジェクトへの参照があるためです(内部にはアイテムを保持List<T>する配列があるため)。T[]

したがって、参照チェーンは次のようになります。- Program.Main()> list->list[0]したがって、オブジェクトがどの世代にあるかに関係なく、GCはこのオブジェクトを収集できません(収集すべきではありません)。

編集:gen 0の収集を開始すると、...list[0]はgen 0 +参照されます(上記を参照)=> GCは収集しませんlist[0]が、gen1に移動します。

于 2012-10-09T22:43:47.837 に答える
1

主なルールは非常に単純で、オブジェクトへの参照が残っていない場合にオブジェクトが収集されます。リストに追加したオブジェクトは収集できません。リストにはそのオブジェクトへの参照があります。リストを収集できません。コードにリストへの参照があります。最後のステートメントまでずっと。また、コレクションを強制するたびに、オブジェクトを次の世代に強制的に移動します。

これについておそらく混乱している唯一のことは、ガベージコレクターがリストにオブジェクトへの参照が格納されていることを確認できることです。それは間違いなくそうです。必然的に、オブジェクトがランダムに消えないようにする必要があります。CLRが行うことの非常に大きな部分は、ガベージコレクターにこれをできるだけ早く検出するために必要な情報を提供することです。

おそらくもっと混乱するのは、コードにリストへの参照があることもわかるということです。これはジッターの重要な部分であり、コードのどの部分がローカル変数を参照しているかを示すテーブルを作成します。最後のステートメントがリストを参照しているため、スニペットでそれを確認することはできません。

于 2012-10-10T00:03:25.320 に答える