考虑这个代码块
public void ManageInstalledComponentsUpdate() { IUpdateView view = new UpdaterForm(); BackgroundWorker worker = new BackgroundWorker(); Update update = new Update(); worker.WorkerReportsProgress = true; worker.WorkerSupportsCancellation = true; worker.DoWork += new DoWorkEventHandler(update.DoUpdate); worker.ProgressChanged += new ProgressChangedEventHandler(view.ProgressCallback); worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(view.CompletionCallback); worker.RunWorkerAsync(); Application.Run(view as UpdaterForm); }
这一切都很好,但我想了解为什么对象(工作者,视图和更新)不会收集垃圾
线程计为根对象; 我不确切知道BackgroundWorker是如何操作的,但似乎主线程方法将在worker实例上访问状态; 因此,工作线程本身将使BackgroundWorker实例保持活动状态,直到(至少)线程退出为止.
当然; 集合还要求所有其他(实时)对象都取消引用工作对象; 另请注意,堆栈变量的集合在调试/发布中可能有所不同,并且附加/不附带调试器.
[编辑]正如也已经注意到的那样; worker(在你的代码中)上的事件处理程序将使"视图"和"更新"对象保持活动状态(通过委托),但不是相反.只要工作者的生命比"视图"和"更新"更短,您就不需要对取消订阅事件感到偏执.我已编辑代码以包含一个"SomeTarget"对象,该对象仅由worker引用:您应该看到此效果(即目标与worker一起死亡).
当线程死亡时,工人被收集:这是证据; 在工人报告退出后你应该看到"工人最终确定":
using System; using System.ComponentModel; using System.Threading; using System.Windows.Forms; class Demo : Form { class ChattyWorker : BackgroundWorker { ~ChattyWorker() { Console.WriteLine("Worker finalized"); } } class SomeTarget { ~SomeTarget() { Console.WriteLine("Target finalized"); } public SomeTarget() { Console.WriteLine("Target created"); } public void Foo(object sender, EventArgs args) { Console.WriteLine("Foo"); } } static void Collect(object sender, EventArgs args) { Console.WriteLine("Collecting..."); GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); timer.Interval = 100; timer.Tick += Collect; timer.Start(); ChattyWorker worker = new ChattyWorker(); worker.RunWorkerCompleted += new SomeTarget().Foo; worker.DoWork += delegate { Console.WriteLine("Worker starting"); for (int i = 0; i < 10; i++) { Thread.Sleep(250); Console.WriteLine(i); } Console.WriteLine("Worker exiting"); }; worker.RunWorkerAsync(); } [STAThread] static void Main() { // using a form to force a sync context Application.Run(new Demo()); } }