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

Mau*_*rez 3 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;
Run Code Online (Sandbox Code Playgroud)

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

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

   System.OutOfMemoryException: 
   in System.Threading.ExecutionContext.CreateCopy()
   in System.Threading._TimerCallback.PerformTimerCallback(Object state)
Run Code Online (Sandbox Code Playgroud)

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

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

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

Han*_*ant 6

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

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

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

  • 如果你的代码花费的时间超过了生产者插入它们的速度,那么你就可以*永远不会赢.在生产者插入这些记录之后更新这些记录的速度永远不应该,你不可能提供保证,只有你可以跟上.您至少需要在该列上添加索引,以便查询不会那么昂贵. (3认同)