2

I have a client application that receives video stream from a server via UDP or TCP socket.

Originally, when it was written using .NET 2.0 the code was using BeginReceive/EndReceive and IAsyncResult. The client displays each video in it's own window and also using it's own thread for communicating with the server. However, since the client is supposed to be up for a long period of time, and there might be 64 video streams simultaneously, there is a "memory leak" of IAsyncResult objects that are allocated each time the data receive callback is called.

This causes the application eventually to run out of memory, because the GC can't handle releasing of the blocks in time. I verified this using VS 2010 Performance Analyzer.

So I modified the code to use SocketAsyncEventArgs and ReceiveFromAsync (UDP case). However, I still see a growth in memory blocks at:

System.Net.Sockets.Socket.ReceiveFromAsync(class System.Net.Sockets.SocketAsyncEventArgs)

I've read all the samples and posts about implementing the code, and still no solution.

Here's how my code looks like:

// class data members
private byte[] m_Buffer = new byte[UInt16.MaxValue];
private SocketAsyncEventArgs m_ReadEventArgs = null;
private IPEndPoint m_EndPoint; // local endpoint from the caller

Initializing:

m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
m_Socket.Bind(m_EndPoint);
m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, MAX_SOCKET_RECV_BUFFER);

//
// initalize the socket event args structure. 
//
m_ReadEventArgs = new SocketAsyncEventArgs();
m_ReadEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(readEventArgs_Completed);
m_ReadEventArgs.SetBuffer(m_Buffer, 0, m_Buffer.Length);
m_ReadEventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
m_ReadEventArgs.AcceptSocket = m_Socket;

Starting the read process:

bool waitForEvent = m_Socket.ReceiveFromAsync(m_ReadEventArgs);
if (!waitForEvent)
{
    readEventArgs_Completed(this, m_ReadEventArgs);
}

Read completion handler:

private void readEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
    if (e.BytesTransferred == 0 || e.SocketError != SocketError.Success)
    {
        //
        // we got error on the socket or connection was closed
        //
        Close();
        return;
     }

     try
     {
          // try to process a new video frame if enough data was read
          base.ProcessPacket(m_Buffer, e.Offset, e.BytesTransferred);
     }
     catch (Exception ex)
     {
          // log and error
     }

     bool willRaiseEvent = m_Socket.ReceiveFromAsync(e);

     if (!willRaiseEvent)
     {
         readEventArgs_Completed(this, e);
     }
}

Basically the code works fine and I see the video streams perfectly, but this leak is a real pain.

Did I miss anything???

Many thanks!!!

oferbar
  • 176
  • 2
  • 16
  • `SocketAsyncEventArgs` and `Socket` implement `IDisposable`...are you making sure that these objects are disposed? – Brad M Feb 06 '14 at 20:45
  • I'm reusing m_ReadEventArgs. I thought the whole point of using SocketAsyncEventArgs was not having a new object on each call, or is it? Thanks for your response. – oferbar Feb 06 '14 at 21:13

1 Answers1

1

Instead of recursively calling readEventArgs_Completed after !willRaiseEvent use goto to return to the top of the method. I noticed I was slowly chewing up stack space when I had a pattern similar to yours.

Brannon
  • 5,324
  • 4
  • 35
  • 83