我正在使用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(单线程单元)。这样它的所有方法都是从same线程,即使调用是在另一个线程上进行的。 COM 负责将调用从一个线程编组到另一个线程。 STA 线程通过泵送消息循环来实现这一点。
然而你所做的是创造another线程并对其进行调用,这与该线程所在的线程不同发电机对象被创建。这并不能解决问题,它仍然是线程不安全的。 COM 仍然封送调用。
重要的是您创建该线程的线程发电机目的。由于它是一个公寓线程对象,因此must在 STA 线程上创建。 Windows 应用程序中通常只有一个,即程序的主线程,通常称为 UI 线程。如果您在不是 STA 的 .NET 工作线程上创建它(就像您在此处所做的那样),那么 COM 将介入并创建一个 STA 线程本身,为组件提供一个好客的家。这很好,但通常是不可取的。
这里没有免费的午餐,你无法神奇地编写一段代码明确地说它不(注册表中的 ThreadingModel 键)支持线程行为。您的下一个最佳选择是创建一个 STA 线程并运行all其上的代码,包括 COM 对象的创建。请注意,您通常必须使用 Application.Run() 来泵送消息循环,许多 COM 服务器假设有一个可用的消息循环。特别是当他们告诉您需要 STA 线程时。您会注意到,当它们行为不当、方法调用陷入僵局或不引发事件时,它们就会这样做。
关于您最初的问题,这是标准的 .NET 行为。垃圾收集器在需要时运行,而不是在您认为应该运行时运行。您可以使用 GC.Collect() 覆盖它,但这很少是必要的。尽管在您的情况下这可能是一个快速修复方法,但 COM 会为每个文件创建一个新线程。 STA 线程给出发电机一个家。使用“调试”+“Windows”+“线程”来查看它们。这些线程在 COM 对象被销毁之前不会停止。这需要终结器线程才能运行。当文件超过 2000 时,您的代码还将消耗所有可用内存并引发 OOM,这也许足以寻找真正的修复方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)