我的BackgroundWorker实例何时被垃圾回收
本文关键字:BackgroundWorker 实例 何时 我的 | 更新日期: 2023-09-27 17:47:24
考虑这个代码块
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);
}
这一切都很好,但我想了解为什么对象(worker、view和update)没有得到垃圾收集的
线程算作根对象;我不知道BackgroundWorker是如何操作的,但似乎主线程方法将访问worker实例上的状态;因此,工作线程本身将保持BackgroundWorker实例处于活动状态,直到(至少)线程退出为止。
当然;集合还要求所有其他(活动)对象都已取消引用worker对象;还要注意的是,堆栈变量的集合在调试/发布以及附加/不附加调试器时可能会有所不同。
[编辑]正如已经指出的那样;worker上的事件处理程序(在您的代码中)将保持"视图"answers"更新"对象的活动状态(通过委托),但不能反过来。只要工作人员的寿命比"查看"answers"更新"的时间短,你就不必对取消订阅活动产生偏执。我已经编辑了代码,以包含一个仅由工作人员引用的"SomeTarget"对象:您应该看到这种效果(即目标与工作人员一起死亡)。
当线程死亡时,再工人被收集起来:这是证据;在工作者报告退出后,您应该看到"工作者已完成":
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());
}
}
事件处理程序是引用,因此在将事件处理程序附加到工作者之前,它不会被视为"不可访问"。
在ComplicationCall back中,请注意取消挂起事件处理程序。
这些局部变量对象保持活动状态,直到函数退出,也就是表单退出。所以在调用Run之前将它们置空,或者将它们移到不同的上下文中。
public void ManageInstalledComponentsUpdate() {
UpdaterForm form = new UpdaterForm();
FireAndForgetWorker( form );
Application.Run( form ); //does not return until form exits
}
void FireAndForgetWorker( IUpdateView view ) {
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();
}
vsick注意事项:
试着运行下面的程序,你会惊讶于x的永生。
使用系统;
class FailsOnGarbageCollection
{ ~FailsOnGarbageCollection() { throw new NotSupportedException(); } }
class Program{
static void WaitForever() { while (true) { var o = new object(); } }
static void Main(string[] args)
{
var x = new FailsOnGarbageCollection();
//x = null; //use this line to release x and cause the above exception
WaitForever();
}
}