简体   繁体   English

Socket 的扩展方法“ReceiveAsync”的内存泄漏!

[英]Memory leak of the Socket's extension method 'ReceiveAsync'!

I have a long-time running service program based on asynchronous Socket.我有一个基于异步Socket的长时间运行的服务程序。 It's memory usage keep increasing over time when it is being health detected (short time TCP port connect and disconnect) by other devices.当其他设备检测到它的健康状况(短时间 TCP 端口连接和断开连接)时,它的内存使用量会随着时间的推移而不断增加。 I suspect some memory of this type of TCP connection has not been released.我怀疑这种类型的 TCP 连接的一些内存没有被释放。 So I made a simple program for verification:于是我做了一个简单的验证程序:

class Program
{
    static void Main(string[] args) => new Program().Start(args[0] == "server");

    private void Start(bool bStartServer)
    {
        if (bStartServer)
        {
            TcpListener tlToClient = TcpListener.Create(2868);
            tlToClient.Start();
            DoClientService(tlToClient);
            System.Console.WriteLine("start on port 2868...");
            for (int i = 0; i < 10; i++)
            {
                Console.ReadLine();
                GC.Collect();
            }
        }
        else
        {
            for (int i = 0; i < 50000; i++)
            {
                Socket s = new Socket(SocketType.Stream, ProtocolType.Tcp);
                s.Connect("127.0.0.1", 2868);
                s.Shutdown(SocketShutdown.Both);
                s.Close();
            }
            System.Console.WriteLine("all done");
            Console.ReadLine();
        }
    }

    static async Task DoClientService(TcpListener tlToClient)
    {
        while (true)
            Receive(await tlToClient.AcceptSocketAsync().ConfigureAwait(false));
    }

    static async Task Receive(Socket socket)
    {
        while (true)
        {
            await Task.Delay(50).ConfigureAwait(false);
            var read = await socket.ReceiveAsync(new ArraySegment<byte>(new byte[8192], 0, 8192), SocketFlags.None).ConfigureAwait(false);
            if (read == 0)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Dispose();
                return;
            }
        }
    }
}

As the code shows, After server is listening on port 2868, the test client will initiate 50,000 TCP connections continuely, and these connections will be closed after connecting succeed.如代码所示,服务端监听2868端口后,测试客户端会继续发起50000个TCP连接,连接成功后关闭这些连接。 When the server receiving buffer is set to 8,192 the server will take 800MB memory after the test ends.当服务器接收缓冲区设置为8192时,测试结束后服务器将占用800MB内存。

I suspect that there is a bug in the internal implementation of Socket's extension method ReceiveAsync which lead to the reveive buffer area can't be released.怀疑是Socket的扩展方法ReceiveAsync的内部实现存在bug,导致reveive缓冲区无法释放。

The code has been simplified, it will only test the memory leak problem.代码已经简化,只会测试内存泄漏问题。

Any help would be appreciated!任何帮助,将不胜感激!

You should create one buffer and reuse it.您应该创建一个缓冲区并重复使用它。 Garbage collection is not aggressive, which would explain the leak.垃圾收集不是激进的,这可以解释泄漏。 More specifically, this line var Buffer = new ArraySegment<byte>(new byte[8192], 0, 8192);更具体地说,这一行var Buffer = new ArraySegment<byte>(new byte[8192], 0, 8192);

should be out of your while loop and it should be passed into ReciveAsync.应该在你的 while 循环之外,它应该被传递到 ReciveAsync。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM