SendToAsync内存泄漏?

时间:2010-07-19 18:10:05

标签: c# sockets asynchronous network-programming sendto

我有一个简单的.net 3.5sp1 windows应用程序(在C#中)充当UDP服务器。它侦听端口,从端点接收数据,然后将其接收的内容重新发送到另一个端点(即中继,用于直播数据流)。我所经历的是在连接启动约20分钟后,它开始恶化。另外我注意到它每秒吞噬大约50-100K的内存,这在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的内存泄漏经验?

更新:

初始化套接字时,我实例化一个状态对象(仅执行一次)。 state对象有一个名为“buffer”的属性,它是一个字节数组。我从套接字接收数据异步如下:

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)上,我正在检索异步对象,然后将字节缓冲区传递给另一个函数进行处理,然后调用上面发布的代码以便重新传输到另一端(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对象有关,并且async函数挂在这些对象上,每个数据包一个(每秒33个数据包,可以快速加起来)。我再次查看了SocketAsyncEventArgs的MSDN文档,我注意到在提供的服务器“示例”代码中,他们使用了一个SocketAsyncEventArgs对象池。我认为它的设计并不像我使用它那样。我认为重点是不必为每次调用实例化这些缓冲区等,因此重用它们并使服务器具有更好的性能。

4 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:0)

分配readData缓冲区在哪里?
整个接收/发送循环是否在同一范围内?

答案 2 :(得分:0)

您可以随时使用

!gcroot <address>

跟踪谁在您的对象上保留引用。请参阅CLR Memory Leak

答案 3 :(得分:0)

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

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

如果您正在制作流媒体视频,则可能需要跳过帧或丢弃整个数据包。