GC.Collect 后 C# 引用对象仍然存在

C# reference object still alive after GC.Collect

On statement var list = Foo(); CLR 在行 GC.Collect(2) 进入调试模式后执行 Library = null;;列表仍然有 10 个元素。为什么它没有设置为空?它为哪个对象执行 Library = null;?

public class Book
{
    public string FirstName { get; set; }

    public string LastName { get; set; }
}

public class Controller : IDisposable
{
    public List<Book> Library = null;

    public Controller()
    {
        Console.WriteLine("Controller created.");
        Console.WriteLine("List created.");
        Library = new List<Book>();
        for (int i = 0; i < 10; i++)
        {
            Library.Add(new Book { FirstName = "FirstName" + i.ToString(), LastName = "LastName" + i.ToString() });
        }
    }
    public void Dispose()
    {
        Library = null; // Just for check
        Console.WriteLine("List disposed.");
    }
}

class Program
{
    private static List<Book> Foo()
    {
        using (var lib = new Controller())
        {
            return lib.Library;
        }
    }
    static void Main(string[] args)
    {
        var list = Foo();
        GC.Collect(0);
        GC.Collect(1);
        GC.Collect(2);
    }
}

Foo() return 是对 Controller 中创建的图书列表的引用,该引用存储在变量 list 中。垃圾收集器将不会收集书籍列表,因为您的程序仍在引用它。当没有包含对其的引用的变量时,书籍列表将被垃圾收集。

如果你调用Foo()而不存储return值,那么书籍列表将被标记为垃圾收集,并最终在垃圾收集器运行时被收集。

"For which object it executing Library = null;?"

Disposeusing 块的末尾自动调用,因此这段代码是 Library 设置为 null:

private static List<Book> Foo()
{
    using (var lib = new Controller())
    {
        return lib.Library;
    } // <-- Dispose is called here on 'lib'
}

请注意,在 为 return 语句获得对 Library 的引用后,这被称为 ,因此该方法仍然是 returns有效参考。

并且因为返回了对列表的引用(而不是空引用),这就是为什么 list 不是 null


如果您在 获取引用之前有意调用Dispose ,那么Library 将是null:

private static List<Book> Foo()
{
    using (var lib = new Controller())
    {
        lib.Dispose();
        return lib.Library;  // Now 'Library' is null
    } 
}