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

        }
    }
}

list 对象在 Gen 2 中,而它是第 0 代中唯一的引用 list[0] 对象。它怎么知道不在 GC.Collect(0) 中收集它?

4

3 回答 3

2

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

执行摘要是 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],而是将其移至 gen 1。

于 2012-10-09T22:43:47.837 回答
1

主要规则非常简单,当没有对它的引用时,对象就会被收集。您添加到列表中的对象无法被收集,列表中有对它的引用。无法收集该列表,您的代码有对其的引用。一直到最后一条语句。每次强制收集时,您都会强制对象移动到下一代。

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

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

于 2012-10-10T00:03:25.320 回答