views:

110

answers:

4

I have a simple .net 3.5sp1 windows application (in C#) that acts as a UDP server. It listens on a port, receives data from an endpoint, and then retransmits what it receives to another endpoint (i.e. a relay, for a live broadcast data stream). What I'm experiencing is after the connection is up for about 20 minutes, it starts to deteriorate. Also I notice that it is gobbling up about 50-100K of memory per second, which doesn't ever get released after GC. I have to close the app and restart it. Not good. I have narrowed down the problem to the following code, which does the retransmission to the other side:

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);

Does anyone have any experience with memory leaks with SendToAsync?

UPDATE:

I instantiate a state object (only done once) when the socket is initialized. The state object has a property called "buffer", which is a byte array. I receive data async from the socket like such:

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);
}

And, then on my callback (ReceiveDataCB), I am retrieving the async object, and then passing the byte buffer to another function for processing, which in turn calls the code posted above for retransmission to the other side (state.buffer becomes readData).

UPDATE #2:

Following my gut, I changed the sending code to the following, getting rid of SocketAsyncEventArgs and 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);

And, of course, I added an "echoCB" callback that does nothing other than calling EndSendTo. The memory leak is now gone! I suspect it had something to do with creating so many SocketAsyncEventArgs objects, and the async function hanging onto these, one for each packet (at 33 packets per second, that can add up fast). I looked once again at the MSDN documentation for SocketAsyncEventArgs, and I noticed that on the server "example" code provided, they used a pool of SocketAsyncEventArgs objects. I don't think its really designed to work the way I was using it. I think the whole point is to not have to instantiate these buffers, etc, for each call, therefore reusing them and allowing the server better performance.

A: 

Where is the readData buffer allocated?
Is the whole receive/send loop inside the same scope?

EricSchaefer
see my edits I posted
Rodney Burton
A: 

You can always use

!gcroot <address>

to track down who's keeping a reference on your objects. See CLR Memory Leak.

Remus Rusanu
A: 

I think your relay node is doing much more work receiving data and is ultimately receiving data faster than it is sending. As data comes in off the wire, you are allocating memory for it and queuing that up to be sent async style, but your outgoing data may be sent much slower than you are receiving (and allocating for) new data, resulting in an overload of incoming data. This is often the case on network nodes that have higher download speeds than upload speeds.

You can throttle the amount of incoming data you accept and allocate for. You can use a callback to do this (args.Completed) by tracking the amount of data queued up to be sent versus actually sent (by tracking sent in the callback). If the amount of data waiting to be sent is larger than some arbitrary limit, don't accept new data.

If you are doing streaming video, you may have to skip frames or discard entire packets.

jscharf
Good thought. I am doing streaming audio, however it does not get behind or skip. In fact, I am monitoring the bytes/in bytes/out and they are the same. I am able to maintain about 1/3 second delay due to transmission.
Rodney Burton
A: 

See my answer posted in UPDATE #2 (above)

Rodney Burton