具有自动复位的计时器导致System.OutOfMemoryException

时间:2014-01-03 13:20:06

标签: c# multithreading timer

我有以下代码,在某个表上运行“select”,需要每200毫秒监控一次

timerMonitoreoOrdenes = new System.Timers.Timer(FRECUENCIA_MONITOREO_ORDENES);
timerMonitoreoOrdenes.Elapsed += new ElapsedEventHandler(timerMonitoreoOrdenes_Elapsed);
timerMonitoreoOrdenes.Enabled = true;
timerMonitoreoOrdenes.AutoReset = true;

timerMonitoreoOrdenes_Elapsed方法中,我运行一个返回DataSet的存储过程 对于每一行,我创建一个存储在内存Queue

中的新Object

该程序旨在一直运行(如Windows服务),但程序运行几个小时后,我收到此异常

   System.OutOfMemoryException: 
   in System.Threading.ExecutionContext.CreateCopy()
   in System.Threading._TimerCallback.PerformTimerCallback(Object state)

我这样做的原因是因为有一个外部程序在状态= 0的DB上插入记录,我需要记录这些记录,处理它们并设置status = 1。有一些线程从队列中获取记录

重要的是要提到这是一个实时交易应用程序,信息中的1秒延迟太高

  • 我想知道是否由于计时器自动复位而抛出System.OutOfMemoryException?
  • 我应该创建一个Thread还是使用Thread.Sleep而不是Timer来检查另一个进程插入的某些记录?

3 个答案:

答案 0 :(得分:6)

当然,这很有可能。用AutoReset = true勾选的计时器是一个定时炸弹。如果Interval太短,事情会发生严重错误。使用200毫秒是非常危险的,dbase更新查询可能需要更长时间。特别是如果您要查找的列未编入索引。

即使前一个事件处理程序未完成,您的Elapsed事件处理程序也会再次运行。在另一个线程池线程上。每个线程将消耗一兆字节的内存,以及查询和处理所需的任何内容。这只是继续,创造更多的线程。线程池管理器将努力限制这一点,但允许运行的最大线程数非常高。足够高,导致任意代码最终被OOM覆盖。

使用AutoReset = false并在Elapsed事件处理程序的末尾再次调用Start()。并使用至少接近实际处理时间的合理间隔。并在该列上添加索引,以便dbase引擎不必查看表中的每条记录。

答案 1 :(得分:0)

您好我曾经这样做了一次,我不得不分割代码并制作Windows服务,我建议您也这样做,使用Windows服务每10分钟检查一次,每分钟或类似的事情,以及运行程序。

如果你正在使用Windows窗体,主系统将会崩溃很多次,我希望我能帮助你解决这个问题。

答案 2 :(得分:0)

您是否确定在不再需要计时器时通过调用Dispose()方法正确处理计时器?如果不这样做,就会造成内存泄漏。