2

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.

4

4 回答 4

5

您可能没有调用 SocketAsyncEventArgs.Dispose()

于 2011-08-29T06:44:44.647 回答
0

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

于 2010-07-19T18:13:45.880 回答
0

您可以随时使用

!gcroot <address>

追踪谁在您的对象上保留参考。请参阅CLR 内存泄漏

于 2010-07-19T18:14:02.507 回答
0

我认为您的中继节点正在做更多的工作来接收数据,并且最终接收数据的速度比发送数据的速度要快。当数据从网络中传入时,您正在为其分配内存并将其排队等待以异步方式发送,但是您的传出数据的发送速度可能比您接收(和分配)新数据的速度慢得多,从而导致过载传入的数据。这通常发生在下载速度高于上传速度的网络节点上。

您可以限制您接受和分配的传入数据量。您可以使用回调来执行此操作 ( args.Completed ),方法是跟踪排队等待发送的数据量与实际发送的数据量(通过跟踪回调中发送的数据)。如果等待发送的数据量大于某个任意限制,则不要接受新数据。

如果您正在处理流式视频,您可能必须跳过帧或丢弃整个数据包。

于 2010-07-19T18:28:02.490 回答