C#引用对象在GC.Collect之后仍处于活动状态

C#引用对象在GC.Collect之后仍处于活动状态,c#,garbage-collection,C#,Garbage Collection,在语句varlist=Foo()上CLR执行库=null在第GC.Collect(2)行上以调试模式步进后;列表仍然有10个元素。为什么它没有设置为null?它为哪个对象执行Library=null public class Book { public string FirstName { get; set; } public string LastName { get; set; } } public class Controller : IDisposable {

在语句var
list=Foo()上CLR执行
库=null在第
GC.Collect(2)
行上以调试模式步进后;列表仍然有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);
    }
}
公共课堂教材
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
}
公共类控制器:IDisposable
{
公共列表库=null;
公共控制员()
{
Console.WriteLine(“控制器已创建”);
Console.WriteLine(“创建列表”);
库=新列表();
对于(int i=0;i<10;i++)
{
添加(新书{FirstName=“FirstName”+i.ToString(),LastName=“LastName”+i.ToString()});
}
}
公共空间处置()
{
Library=null;//仅供检查
Console.WriteLine(“列表已处理”);
}
}
班级计划
{
私有静态列表Foo()
{
使用(var lib=new Controller())
{
返回库;
}
}
静态void Main(字符串[]参数)
{
var list=Foo();
GC.Collect(0);
GC.Collect(1);
GC.Collect(2);
}
}
Foo()
返回对在
Controller
中创建的书籍列表的引用,该引用存储在变量
list
中。垃圾收集器不会收集书籍列表,因为您的程序仍在引用它。当没有包含引用的变量时,书籍列表将被垃圾收集

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

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

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

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

当您调用
GC.Collect
时,GC(1)不保证遵守您执行收集的请求,并且(2)当您连接了调试器时,其行为会有所不同。删除对该列表的所有引用后,您如何检查该列表?@JoeSewell,好吧,为什么主函数中的列表不为null?我在dispose方法中将他设置为null。@AlexGorbunov如果没有,您将引用列表的属性设置为null,但这不会影响可能获得该引用的任何其他变量或属性。我认为您对引用类型的工作方式感到困惑。如果您执行
var x=new List();变量y=x;x=零
,则
x
null
,但
y
仍在引用列表。把列表想象成一个在某处占用内存的对象。然后
x
y
只是指内存中的那个位置。如果将其中一个设置为
null
,它将不再指向那里,但这不会改变该内存位置上的内容,因此另一个仍然引用
列表。如果存在对它的活动引用,
GC
将不会处理它。