2014-01-03 2 views
3

У меня есть следующий фрагмент кода, который запускает «выбрать» на определенную таблицу, которая должна контролироваться каждые 200 милисекундТаймер с автосбросом вызывает System.OutOfMemoryException

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

В timerMonitoreoOrdenes_Elapsed методе я бегу хранимая процедура, которая возвращает DataSet и для каждой строки, я создаю новый объект, который хранится в памяти Queue

программа предназначена для быть запущенно все время (как сервис Windows), но после того, как программа работает для Несколько часов я получаю это исключение

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

Причина, по которой я делаю это, как это Becase есть внешняя программа, которая вставляет записи в БД со статусом = 0, и мне нужно, чтобы получить эти записи, процесс их и установить статус = 1 , Есть некоторые темы, которые принимают записи из очереди

Важно отметить, что это для приложения РЕАЛЬНОГО ВРЕМЕНИ-ТРЕЙДИНГ, что 1 вторая задержка информации слишком высока

  • Я хочу знать, возникает ли исключение System.OutOfMemoryException из-за автосекретаря таймера?
  • Должен ли я создать Thread или использовать Thread.Sleep вместо Timer для проверки определенных записей, которые были вставлены другим процессом?
+0

Ну, вы описали, как вы помещаете данные из своего DataSet в очередь, но ни в коем случае не предлагаете вам что-либо выходить из очереди.Другая мысль, которая возникает, заключается в том, что если SQL-запрос занимает в среднем более 200 мс, тогда вы столкнетесь с множеством проблем. Более подробная информация о том, что вы делаете, прежде чем дать ответ. А также, возможно, почему вы это делаете, поскольку может быть лучшее решение вашей исходной проблемы, чем обычные выборки в таблице БД. – Chris

+0

@Chris Я добавил дополнительную информацию к вопросу. Если вам нужна дополнительная информация, я могу предоставить их. –

+0

Сверху моей головы. Я не помню, чтобы сам System.Timers.Timer мешал повторному вводу обратного вызова. Может быть, ваш обратный вызов снова вызван до завершения предыдущего вызова? Что произойдет, если вы отключите таймер из обратного вызова, чтобы этого не произошло? –

ответ

6

Несомненно, это вполне возможно. Таймер с тиреровкой AutoReset = true - это тикающая бомба замедленного действия. Вещи идут кардинально неправильно, если интервал слишком короткий. Использование 200 мсек довольно рискованно, запросы на обновление базы данных могут занять больше времени. В частности, если колонка, которую вы ищете, не индексируется.

Обработчик обработанного события «Истекший» запускается снова, даже если предыдущий не завершен. В другом потоке потока. Каждый поток потребляет мегабайт памяти, плюс все, что вам нужно для запроса и обработки. Это просто продолжается, создавая все больше потоков. Менеджер пула потоков попытается ограничить это, но максимальное число потоков позволяет запустить очень высокий. Достаточно высокий, чтобы вызвать произвольный код в конечном итоге с OOM.

Используйте AutoReset = false и снова вызовите Start() в конце обработчика событий Elapsed. И используйте разумный интервал, который по крайней мере близок к фактическому времени обработки. И добавьте индекс в этот столбец, чтобы движок dbase не смотрел на каждые записей в таблице.

+0

Интервал SET в коде и указан в вопросе как 200 мс –

+0

Хорошо, все еще очень короткое. Нет никакой причины рисковать, это будет * никогда * работать лучше, если эти запросы обновления перекрываются. Скорее наоборот, вы можете обрабатывать одну и ту же запись более одного раза. Используйте профайлер памяти, если он все еще падает. –

+0

Как еще можно записывать записи из таблицы БД так быстро, насколько это возможно. У меня есть продюсер, который вставляет их на стол так быстро, как 700 записей в минуту –

0

Привет, я сделал это один раз, мне пришлось разделить код и сделать сервис Windows, я рекомендую вам сделать то же самое, использовать службу Windows, чтобы проверять час каждые 10 минут, каждую минуту или что-то вроде и выполняйте процедуры.

Если вы работаете с окнами, основная система будет разбита много раз, я надеюсь, что смогу помочь вам с этими советами.

+1

Будет ли это по существу уменьшать объем используемой памяти по какой-либо причине? Он уже выполняет проверки с регулярными интервалами, за исключением того, что OP делает 200 мс вместо минут или более. – Chris

+0

@ Крис да, это будет, потому что служба Windows работает на backgroud, и не имеет значения, сколько времени он будет использовать – ricardorios

+0

. Дело в том, что если выполняемый код будет таким же, то такое же количество объектов будет и тот же объем памяти будет выделен. Создание службы Windows может изменить некоторые вещи, но не то, сколько памяти используется, потому что она делает то же самое. – Chris

0

Вы уверены, что правильно выбрали таймер, вызвав метод Dispose(), когда таймер больше не нужен? Если вы этого не сделаете, это создаст утечку памяти.

+1

Если таймер должен запускаться до тех пор, пока программа запускается, когда и как я могу назвать Dispose? –

+0

Хотя вы правы в том, что таймер должен оставаться в живых, то то же самое можно применить к любым объектам, которые вы создаете в своем рабочем потоке. Не могли бы вы оставить ссылки на какие-либо объекты, созданные где-нибудь, или не правильно распоряжаться другими объектами? – Chris

+0

Если OutOfMemoryExcetption происходил в моем коде, StackTrace показал бы, что –

Смежные вопросы