Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timer with autoreset is causing System.OutOfMemoryException

I have the following piece of code, that runs a "select" on certain table that needs to be monitored every 200 miliseconds

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

In the timerMonitoreoOrdenes_Elapsed method I run a stored procedure that returns a DataSet and for each row I am creating a new Object that is stored in memory Queue

The program is designed to be running all the time (like a windows service) but after the programs runs for a few hours I am getting this exception

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

The reason that I am doing this like this is becase there is an external program that is inserting records on the DB with status=0 and I need to take those records, process them and set the status=1. There are some Thread that are taking records from the Queue

Is important to mention that This is for a REAL-TIME-TRADING application that 1 second delay in the information is too high

  • I want to know if the System.OutOfMemoryException is being thrown because of the timer autoreset ?
  • Should I create a Thread or use Thread.Sleep instead of a Timer to check for certain records that were inserted by another process ?
like image 384
Mauricio Gracia Gutierrez Avatar asked Mar 22 '23 03:03

Mauricio Gracia Gutierrez


1 Answers

Sure, that is quite possible. A Timer that's ticking with AutoReset = true is a ticking time bomb. Things go drastically wrong if the Interval is too short. Using 200 msec is pretty risky, dbase update queries can easily take longer than that. Particularly so if the column you are looking for isn't indexed.

Your Elapsed event handler will run again even though the previous one isn't completed. On another thread-pool thread. Each thread will consume a megabyte of memory, plus whatever you need for the query and processing. This just continues, creating ever more threads. The thread-pool manager will make an effort to limit this but the maximum number of threads is allows to run is very high. High enough to cause arbitrary code to eventually fall over with OOM.

Use AutoReset = false and call Start() again at the end of your Elapsed event handler. And use a reasonable Interval that's at least close to the actual processing time. And add an index on that column so the dbase engine doesn't have to look at every record in the table.

like image 118
Hans Passant Avatar answered Apr 08 '23 17:04

Hans Passant