为何C#中已置null并调用GC.Collect(),Starter对象仍未被GC回收?
原因解释
问题的核心在于后台任务的Lambda表达式隐式捕获了Starter实例的引用,具体细节如下:
- 你在
Start方法里的Task.Run中使用了成员变量a,C#里访问实例成员本质是this.a,编译器会自动让这个Lambda表达式持有当前Starter对象(this)的引用。 - 后台Task处于持续运行的状态,它的执行上下文会持有这个Lambda委托的引用,而Lambda又握着Starter实例的引用——GC判断对象是否可回收的依据是是否存在有效引用链,所以这个Starter实例会被判定为"仍在被使用",不会被回收。
- 你把变量
s赋值为null,只是切断了Main方法里对Starter实例的引用,但后台任务的Lambda还攥着实例的引用,所以实例无法被GC回收,后台的循环自然会一直跑下去。
如果想验证这个逻辑,可以修改Lambda里的代码,比如去掉对a的引用,改成一个不访问实例成员的空循环:
Task.Run(() => { while (true) { Console.WriteLine("循环运行中"); Thread.Sleep(1000); } });
这时候再运行代码,Starter实例就会被GC回收,因为Lambda没有捕获this引用了。
内容的提问来源于stack exchange,提问作者Cavid Haciyev
相关产品推荐
相关产品推荐

