3

I have a long-time running service program based on asynchronous 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. I suspect some memory of this type of TCP connection has not been released. 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. When the server receiving buffer is set to 8,192 the server will take 800MB memory after the test ends.

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.

The code has been simplified, it will only test the memory leak problem.

Any help would be appreciated!

zts9989
  • 31
  • 3

1 Answers1

2

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

should be out of your while loop and it should be passed into ReciveAsync.

Alex Williams
  • 53
  • 1
  • 7