Утечка памяти SendToAsync? - PullRequest
2 голосов
/ 19 июля 2010

У меня есть простое Windows-приложение .net 3.5sp1 (на C #), которое работает как UDP-сервер.Он прослушивает порт, получает данные от конечной точки, а затем повторно передает то, что он получает, другой конечной точке (т. Е. Ретрансляции для потока данных прямого вещания).Что я испытываю, так это то, что после того, как соединение установлено примерно на 20 минут, оно начинает ухудшаться.Кроме того, я заметил, что он поглощает около 50-100 КБ памяти в секунду, которая никогда не выпускается после GC.Я должен закрыть приложение и перезапустить его.Нехорошо.Я сузил проблему до следующего кода, который выполняет повторную передачу на другую сторону:

var sendBuffer = new byte[readCount];
Array.Copy(readData, sendBuffer, readCount);
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.RemoteEndPoint = p.EP;
args.SetBuffer(sendBuffer, 0, sendBuffer.Length);
SwitchWindow.LineSocket.SendToAsync(args);

Есть ли у кого-нибудь опыт с утечками памяти с SendToAsync?

ОБНОВЛЕНИЕ:

Я создаю экземпляр объекта состояния (выполняется только один раз) при инициализации сокета.У объекта состояния есть свойство, называемое «буфер», которое является байтовым массивом.Я получаю асинхронные данные из сокета следующим образом:

private void beginReceiveData(ref MessageState state)
{
    var ipeSender = new IPEndPoint(IPAddress.Any, 0);
    var epSender = (EndPoint)ipeSender;

    state.workSocket = LineSocket;
    state.EP = epSender;
    state.workSocket.BeginReceiveFrom(state.buffer, 0, MessageState.BufferSize,
        SocketFlags.None, ref epSender,
        new AsyncCallback(ReceiveDataCB),
        state);
}

И затем по моему обратному вызову (ReceiveDataCB) я ​​получаю асинхронный объект, а затем передаю байтовый буфер другой функции для обработки, которая вturn вызывает код, указанный выше, для повторной передачи на другую сторону (state.buffer становится readData).

ОБНОВЛЕНИЕ № 2:

Следуя своей интуиции, я изменил отправкукод к следующему, избавляясь от SocketAsyncEventArgs и SendToAsync:

var sendBuffer = new byte[readCount];
Array.Copy(readData, sendBuffer, readCount);
SwitchWindow.LineSocket.BeginSendTo(
    sendBuffer, 0, sendBuffer.Length, SocketFlags.None,
    p.EP, new AsyncCallback(echoCB), null);

И, конечно, я добавил обратный вызов echoCB, который ничего не делает, кроме вызова EndSendTo.Утечка памяти исчезла!Я подозреваю, что это как-то связано с созданием такого количества объектов SocketAsyncEventArgs и асинхронной функцией, висящей на них, по одному для каждого пакета (при 33 пакетах в секунду, которые могут быстро складываться).Я еще раз просмотрел документацию MSDN для SocketAsyncEventArgs и заметил, что на предоставленном «примере» кода сервера они использовали пул объектов SocketAsyncEventArgs.Я не думаю, что он действительно разработан, чтобы работать так, как я его использовал.Я думаю, что весь смысл состоит в том, что не нужно создавать экземпляры этих буферов и т. Д. Для каждого вызова, поэтому их повторное использование и повышение производительности сервера.

Ответы [ 4 ]

5 голосов
/ 29 августа 2011

Возможно, вы не вызываете SocketAsyncEventArgs.Dispose ()

0 голосов
/ 19 июля 2010

Вы всегда можете использовать

!gcroot <address>

, чтобы отследить, кто хранит ссылку на ваши объекты.См. Утечка памяти в CLR .

0 голосов
/ 19 июля 2010

Я думаю, что ваш ретрансляционный узел выполняет намного больше работы, получая данные, и в конечном итоге получает данные быстрее, чем отправляет.Когда данные поступают по проводам, вы выделяете для них память и ставите ее в очередь для асинхронного стиля, но ваши исходящие данные могут отправляться намного медленнее, чем вы получаете (и выделяете) новые данные, что приводит к перегрузкевходящие данные.Это часто имеет место на сетевых узлах, которые имеют более высокие скорости загрузки, чем скорости загрузки.

Вы можете регулировать количество входящих данных, которые вы принимаете и выделяете.Вы можете использовать обратный вызов для этого ( args.Completed ), отслеживая объем данных, поставленных в очередь, по сравнению с фактически отправленными (путем отслеживания отправленных в обратном вызове).Если объем данных, ожидающих отправки, превышает некоторый произвольный предел, не принимайте новые данные.

Если вы выполняете потоковое видео, возможно, вам придется пропускать кадры или отбрасывать целые пакеты.

0 голосов
/ 19 июля 2010

Где выделен буфер readData?
Весь ли цикл приема / отправки находится в той же области видимости?

...