线程不活动时释放资源

我正在使用BackgroundWorker,在其中我使用foreach循环,在其中创建新线程,等待它完成,然后报告进度并继续foreach循环。 这就是我所说的:

private void DoWork(object sender, DoWorkEventArgs e) { var fileCounter = Convert.ToDecimal(fileNames.Count()); decimal i = 0; foreach (var file in fileNames) { i++; var generator = new Generator(assembly); var thread = new Thread(new ThreadStart( delegate() { generator.Generate(file); })); thread.SetApartmentState(ApartmentState.STA); thread.Start(); while (thread.IsAlive); // critical point int progress = Convert.ToInt32(Math.Round(i / fileCounter * 100)); backgroundWorker.ReportProgress(progress); } } 

问题是在线程完成后(在通过“临界点”线之后)没有释放内存。 我认为当线程不活动时,将释放与之关联的所有资源。 但显然这不是真的。 任何人都可以向我解释为什么以及我做错了什么。 谢谢。

你设法关闭了组件,告诉你你做错了什么。 但是你没有真正解决问题。 不支持线程的组件需要STA,Single Threaded Apartment。 所以它的所有方法都是从同一个线程调用的,即使调用是在另一个线程上进行的。 COM负责将调用从一个线程封送到另一个线程。 STA线程通过泵送消息循环使其成为可能。

但是你所做的是创建另一个线程并对其进行调用,这与创建生成器对象的线程不同。 这并没有解决问题,它仍然是线程不安全的。 COM仍在召集电话。

重要的是你创建生成器对象的线程。 由于它是一个单元线程对象,因此必须在STA线程上创建。 Windows应用程序中通常只有一个,即程序的主线程,通常称为UI线程。 如果你在不是STA的.NET工作线程上创建它,就像你在这里一样,那么COM将介入并创建一个STA线程本身,为组件提供一个好客的家。 这很好,但通常是不受欢迎的。

这里没有免费的午餐,你不能神奇地制作一大堆代码, 明确表示它没有(注册表中的ThreadingModel键)支持线程行为就像它一样。 您的下一个最佳选择是创建一个STA线程并运行其中的所有代码,包括创建COM对象。 请注意,您通常必须使用Application.Run()来填充消息循环,许多COM服务器都假定有一个可用。 特别是当他们告诉你需要一个STA线程时。 你会注意到他们在行为不端时会这样做,在方法调用上遇到僵局或者没有引发事件。

关于您的原始问题,这是标准的.NET行为。 垃圾收集器在需要时运行,而不是在您认为应该运行时运行。 您可以使用GC.Collect()覆盖它,但这很少需要。 尽管在您的情况下它可能是一个快速修复,但COM为每个文件创建一个新线程。 STA线程给发电机一个家。 使用Debug + Windows + Threads查看它们。 在销毁COM对象之前,这些线程不会停止。 这需要终结器线程运行。 当有超过两千个文件时,你的代码也将消耗所有可用的内存并使用OOM炸弹,或许有足够的理由寻找真正的修复。

这可能是因为垃圾收集不是立竿见影的。 在线程超出范围后尝试收集:
编辑:
您还需要实现一种更好的方法来等待线程完成其他忙等待( while (thread.IsAlive); )以节省CPU时间,您可以使用AutoResetEvent

 private void DoWork(object sender, DoWorkEventArgs e) { var fileCounter = Convert.ToDecimal(fileNames.Count()); decimal i = 0; var Event = new AutoResetEvent(false); foreach (var file in fileNames) { i++; var generator = new Generator(assembly); { var thread = new Thread(new ThreadStart( delegate() { generator.Generate(file); Event.Set(); })); thread.SetApartmentState(ApartmentState.STA); thread.Start(); //while (thread.IsAlive); // critical point Event.WaitOne(); } GC.Collect(); int progress = Convert.ToInt32(Math.Round(i / fileCounter * 100)); backgroundWorker.ReportProgress(progress); } } 

生成方法从UI控件获取数据?