我有一个控制台应用程序,它以预定的方式运行作业。 工作做两件事:
1-)运行SQL语句 2-)通过电子邮件发送该声明的结果
如果我以顺序形式运行作业,一切都按预期工作,作业运行,操作期间内存消耗增加,然后释放内存,但是如果我并行运行作业,使用任务并行库,毕竟作业完成后,内存消耗与顺序选项相比仍然高得多,而其他作业也会继续增加内存消耗。
更具体地说,我使用了以下测试用例:
顺序:(完成循环并明确收集GC用于测试目的,内存消耗约为55兆字节)
for (int j = 0; j < 3; j++)
{
for (int i = 0; i < 15; i++)
{
var job = new BIJob(reportData);
job.Execute();
}
Thread.Sleep(10000);
}
并行:(完成循环并明确收集GC以用于测试目的,内存消耗大约为85兆字节)
for (int j = 0; j < 3; j++)
{
for (int i = 0; i < 15; i++)
{
Task jobRunTask = Task.Factory.StartNew(() =>
{
var job = new BIJob(reportData);
job.Execute();
});
}
Thread.Sleep(10000);
}
45次迭代后内存消耗差异大约为30兆字节,并行版本中没有收集额外内存。
可能导致这种行为的原因是什么?任何想法/意见表示赞赏。
答案 0 :(得分:1)
当您并行执行多个操作时,您需要存储足够的内存来处理每个并行操作,而不是一次只在内存中使用一个工作集。您还有其他线程,每个线程都会消耗内存。
这些操作的内存无法在实际完成之前被回收。您只是开始循环中的操作,而不是等待它们完成,因此,只要您正在检查它们,它们就不一定有资格收集。如果您等待所有操作实际完成,那么他们将符合条件进行收集,尽管GC当然可以等待,只要它想要实际上收集他们。
答案 1 :(得分:0)
任务并行库将简单地保留它创建的一些线程以防以后需要它们,因为创建新的线程是一个相对昂贵的操作(在内存和CPU方面)。
关于内存泄漏:只要资源没有压力,TPL使用的线程池就没有理由释放任何线程。 如果要测试内存泄漏,可以简单地增加循环次数。在循环1000次或1000000次之后,内存使用应该没有区别。