简体   繁体   中英

C# reference object still alive after GC.Collect

On statement var list = Foo(); CLR executing Library = null; after stepping in debug mode on line GC.Collect(2) ; list is still have 10 elements. Why it does no set to null? For which object it executing 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() returns a reference to the list of books created in Controller , and that reference is stored in the variable list . The garbage collector will not collect the list of books because it is still being referred to by your program. The list of books will be garbage collected when there are no variable containing a reference to it.

If you call Foo() without storing the return value, then the list of books will be marked for garbage collection, and will be collected eventually when the garbage collector runs.

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

Dispose is called automatically at the end of a using block, so this code is where Library is set to null :

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

Note that this is called after a reference is obtained to Library for the return statement, so the method still returns a valid reference.

And because a reference to the list was returned (and not a null reference), that is why list is not null .


If you purposefully called Dispose before getting the reference, then Library will be null :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM