GC Generations - 收集问题

时间:2012-10-09 22:32:36

标签: c# memory-management garbage-collection

给出以下代码:

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]));

        }
    }
}

列表对象在Gen 2中,而它是gen 0中唯一的引用列表[0]对象。为什么它知道不在GC.Collect(0)中收集它?

3 个答案:

答案 0 :(得分:2)

This article简单地写了它的工作原理;阅读“让世代与写障碍一起工作”部分。 This是另一个很好的博客文章,更详细地解释了技术。

执行摘要是CLR发出的代码,因此它可以检测Gen2对象的写入时间。它将写入记录到进行Gen0收集时检查的数据结构(“卡表”)中;这允许它找到Gen2 - &gt; Gen0引用没有在内存中遍历所有对象的全部成本。

答案 1 :(得分:1)

我是对的,你的问题是,为什么GC没有收集list[0]

如果是这样,那么答案是,因为list内部有对你创建的对象的引用(因为List<T>内部有一个数组T[]来保存项目。)

所以你的参考链看起来像这样:Program.Main() - &gt; list - &gt; list[0],因此GC无法(也不应该)收集此对象,无论您的对象在哪一代。

编辑:你开始收集gen 0的地方,... list[0]在gen 0 +引用(见上文)=&gt; GC 收集list[0],但将其移至第1代。

答案 2 :(得分:1)

主要规则非常简单,当没有任何引用时,会收集一个对象。您添加到列表中的对象无法收集,列表中有对它的引用。列表无法收集,您的代码有参考。一直到最后一个声明。每次强制收集时,都会强制对象移动到下一代。

唯一可能令人困惑的是垃圾收集器可以看到列表存储了对象的引用。它肯定会。必然如此,你不希望对象随机消失。 CLR所做的很大一部分是为垃圾收集器提供了尽快发现它所需的信息。

可能更令人困惑的是,它还可以看到您的代码具有对列表的引用。这是抖动的重要组成部分,它构造了一个表,说明代码的哪一部分引用了局部变量。由于最后一个语句引用了列表,因此您无法在代码段中看到它。