【发布时间】:2014-05-07 04:51:39
【问题描述】:
背景
我已经实现了支持多个消费者线程和多个生产者的消费者-生产者模式。
消费者等待一个脉搏来竞争工作:
private void DistributedConsume()
{
while (_continueConsuming)
{
try
{
Monitor.Wait(_workerLockObject);
IModelJob job = _jobProvider.GetNextJob();
if (job != null)
{
//we found and dequeued job for processing
if (job.JobType != JobType.TerminateWorker)
{
job.PrioritizationStatus = PrioritizationStatus.Dequeued;
try
{
job.Execute();
}
catch (ThreadAbortException)
{
LoggerFacade.Log(LogCategory.Debug, "WorkerController.DistributedConsume(): Thread {0} has been aborted", Thread.CurrentThread.Name);
throw;
}
catch (Exception ex)
{
LoggerFacade.Log(LogCategory.Debug, "WorkerController.DistributedConsume(): Unhandled exception on thread {0}", Thread.CurrentThread.Name);
}
}
else
{
_continueConsuming = false;
}
}
}
catch (ThreadAbortException)
{
LoggerFacade.Log(LogCategory.Debug, "WorkerController.DistributedConsume(): Thread {0} has been aborted", Thread.CurrentThread.Name);
throw;
}
catch (Exception ex)
{
ExceptionHandler.ProcessException(ex, "Unexpected Exception occured attempting to fetch the next job");
}
}
LoggerFacade.Log(LogCategory.OperationalInfo, "WorkerController.DistributedConsume(): Thread {0} is exiting", Thread.CurrentThread.Name);
}
正在执行的作业可能会消耗大量内存,但正如您所见,该作业是在内部范围内声明的,所以我希望该作业在每个循环中都超出范围,因此它及其所有引用的数据将有资格进行垃圾收集。
问题
作业执行,消耗大量内存,作业完成,消费者线程循环回 Monitor.Wait 并等待脉冲。到此阶段,该作业已超出范围,不再被引用。有问题的是,如果没有新作业排队并且线程没有脉冲,则内存使用率保持很高 - 无论我等待多长时间。使用 WinDbg,我还可以看到堆上的作业及其引用的所有后代对象。
这可能会让你认为我有内存泄漏,但 WinDbg 也会验证作业对象是 not 根的。但是,一旦我们向系统提交另一个作业,这个消费者线程拾取,内存就会被释放并清理对象。但如果其他消费者接手这项新工作,则似乎内存没有释放。
我无法理解这一点。我对可能发生的事情的偏执理论都不符合我对 G.C 工作原理的理解。
理论 1. 该作业已进入第 1 代或第 2 代,因此除非系统内存不足,否则不会被收集。但是,一旦线程被唤醒并开始执行另一个作业,它就会收集它是没有意义的,因为内存远非低。
理论 2。我没有第二个理论值得分享。
当系统忙于处理许多自动化作业时,消费者不会等待太久,因此问题不可见。但是在只有用户手动提交一些大型作业的安静日子里,人们提出了关于为什么服务因如此高的内存使用而闲置的问题。因此,这不是一个关键问题,但令人困惑。
任何指针?
谢谢
【问题讨论】:
标签: .net multithreading garbage-collection