Утечка памяти при использовании .net SerialPort, есть ли лучший способ? - PullRequest
3 голосов
/ 23 ноября 2010

У меня есть программа, которая используется для связи с оборудованием через rs232. Это программное обеспечение используется для отображения потока данных, которые проталкиваются через rs232 с аппаратного обеспечения так быстро, как это возможно. Проблема, с которой я сталкиваюсь, заключается в том, что со временем частная память, выделенная программе, взрывается и очень быстро приводит к аварийному завершению программы. Если я отключу оборудование от отправки данных в течение примерно 2 минут, тогда программное обеспечение сможет очистить память, но только если я приостановлю поток данных.

Я использую событие DataReceived из SerialPort, и, похоже, именно в этом и заключается проблема, потому что это вызовет скачок памяти, даже если функция DataReceived внутри него ничего не делает. Единственное, что я могу придумать, это то, что каждый раз, когда возникает это событие, он создает новый поток для запуска, и это происходит так быстро, что у компьютера нет времени для запуска GC, пока поступают данные. *

Есть ли более эффективный способ извлечения данных из объекта SerialPort? Меня волнует только строка, когда я получаю "NewLine"?

Спасибо

Джон Викерс

Ответы [ 4 ]

4 голосов
/ 23 ноября 2010

Это очень необычно, но технически возможно. SerialPort использует потоки пула потоков для вызова обработчика событий DataReceived. Как только он получает один или несколько байтов, он захватывает поток TP, чтобы уведомить ваше приложение. В коде генерации события есть блокировка, только один поток может вызывать ваш обработчик событий одновременно.

Здесь возможный режим сбоя заключается в том, что один из этих вызовов, вероятно первый, входит в цикл в вашем коде, из которого он никогда не выходит. Если вы не настроили свойство «Рукопожатие», устройство может продолжать отправлять и инициировать дополнительные вызовы TP, причем все они блокируются при этой блокировке.

Диагностируйте это из окна Debug + Windows + Threads. Если мое предположение верно, то вы должны увидеть большое количество тем, перечисленных здесь. Один из них должен быть внутри вашего обработчика событий DataReceived, дважды щелкните его и посмотрите на стек вызовов, чтобы увидеть, где он застрял. Память, которую вы видите потребляемой, съедается стеками этих потоков, по одному мегабайту каждый.

Другая возможность состоит в том, что ваш код обработки событий DataReceived будет очень медленным, возможно, вызвав Control.Invoke (). Достаточно медленно, чтобы не успевать за устройством. Теперь вам действительно нужно использовать свойство Handshake для настройки управления потоком. Или исправить то, что делает это так медленно. Между прочим, должно быть очень большое количество событий ErrorReceived, убедитесь, что реализовали это, чтобы вы могли видеть, что все идет не так.

Существует верхний предел количества потоков TP, которые могут быть запущены одновременно. Это довольно щедрый, в 250 раз больше ядер. Это может легко потреблять половину гигабайта памяти на обычной двухъядерной машине.

4 голосов
/ 23 ноября 2010

DataReceived выполняется в другом потоке. У меня были проблемы с очень быстрыми данными, и это событие вызвало у меня проблемы. Из-за этого я создал один поток и сам прочитал данные:

while (this.serialPort.IsOpen)
{
    int b = this.serialPort.ReadByte();
    if (b != -1)
    {
        // data is good here
    }
}

Но, как сказали другие, без какого-либо примера кода мы мало чем можем помочь.

0 голосов
/ 07 июня 2012

Просто чтобы оживить эту проблему.

Я наблюдаю значительную утечку памяти при использовании события DataReceived.

Я использую модем USB 3G, который обеспечивает интерфейс последовательного модема.Я написал крошечную программу, которая просто открывает последовательный порт и подключается к событию DataReceived.Обработчик событий - это просто пустой метод.

Если вы вытаскиваете, память ключа начинает протекать со скоростью около 10 МБ в секунду.Никаких исключений не выдается.

Вращение нового потока и использование синхронного метода Read (...) решило проблему для меня.Теперь я получаю исключение, когда вырываю ключ, с которым могу справиться, и нет утечек памяти.

0 голосов
/ 23 ноября 2010

Я разработал управляемый состоянием язык программирования последовательного порта на C # и считаю, что он действительно решает почти все проблемы с последовательным портом, с которыми все сталкиваются.

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

state Init
  recv();
  $len = length($DATA_PACKET);
  if("$len > 0") {
    log($DATA_PACKET, Debug);
  }
end state

Снимки экрана

Домашняя страница проекта

Скачать

Если у вас есть какие-либо вопросы, пожалуйста, не стесняйтесь спрашивать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...