GC.Collect之后,C#参考对象仍然有效

时间:2019-07-25 19:44:04

标签: c# garbage-collection

在语句list = Foo();上进入调试模式后,在行Library = null;上执行CL GC.Collect(2)时执行CLR;列表仍然有10个元素。为什么不将其设置为null?它针对哪个对象执行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);
    }
}

2 个答案:

答案 0 :(得分:1)

Foo()返回对在Controller中创建的书籍列表的引用,该引用存储在变量list中。垃圾收集器不会收集书籍列表,因为程序仍在引用该列表。如果没有包含引用的变量,则该图书列表将被垃圾回收。

如果在不存储返回值的情况下调用Foo(),则将书籍列表标记为要进行垃圾收集,并且将在运行垃圾收集器时最终对其进行收集。

答案 1 :(得分:1)

  

“它为哪个对象执行Library = null;?”

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

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

请注意,这在之后称为Library语句的对return的引用,因此该方法仍返回有效的引用。

并且由于返回了对列表的引用(而不是空引用),因此list不是null的原因。


如果您有意在获得参考之前致电Dispose ,那么Library将是null

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