C# 异步TCP服务器(Windows服务)内存泄漏

C# 异步TCP服务器(Windows服务)内存泄漏,c#,asynchronous,tcp,server,async-await,C#,Asynchronous,Tcp,Server,Async Await,我正在使用C#中的async/await完成我的第一步,为此,我想编写一个简单的TCP服务器来接收简单字符串(目前)。 因此,我设置了一个Windows服务,其中包含一个正在侦听传入连接的循环,接受这些连接并关闭套接字(我计划将字符串写入日志文件或其他内容,但这必须等到我将要描述的问题得到解决) 无论如何,问题是在通过网络接收到一些字符串后,我的服务占用了以后不会释放的内存。当我启动服务时,没有连接进入,这个过程需要4.716K。当连接被接受时,这个数量会增加(正如我预期的那样),但是资源似乎不

我正在使用C#中的async/await完成我的第一步,为此,我想编写一个简单的TCP服务器来接收简单字符串(目前)。 因此,我设置了一个Windows服务,其中包含一个正在侦听传入连接的循环,接受这些连接并关闭套接字(我计划将字符串写入日志文件或其他内容,但这必须等到我将要描述的问题得到解决)

无论如何,问题是在通过网络接收到一些字符串后,我的服务占用了以后不会释放的内存。当我启动服务时,没有连接进入,这个过程需要4.716K。当连接被接受时,这个数量会增加(正如我预期的那样),但是资源似乎不会在之后被释放

也许,我忽略了一些东西,但我找不到解决方案(尽管“项目”目前只有几行代码),所以我非常感谢您的帮助,伙计们:/

以下是启动/关闭事件处理程序:

protected override void OnStart(string[] args)
{
    this.listener = new TcpListener(IPAddress.Any, 7777);
    this.listener.Start();

    this.worker = new Thread(StartServer);
    this.worker.Start();
}

protected override void OnStop(string[] args)
{
    this.serviceIsRunning = false;
    this.worker.Join();

    // TODO: Cancellation token maybe?
}
这就是服务器循环:

private async void ServerStart(object arguments)
{
    while (serviceIsRunning)
    {
        TcpClient client = await listener.AcceptTcpClientAsync();
        Task requestTask = HandleRequest(client);
    }

    this.listener.Stop();
}
连接处理程序:

private async Task HandleRequest(TcpClient client)
{
    using (var stream = new StreamReader(client.GetStream(), Encoding.UTF8))
    {
        // Do something with it
        string request = await stream.ReadToEndAsync();
    }

    // Gracefully close connection
    client.Close();
}

谢谢

内存使用率非常低。我看到垃圾收集器一直等到3d模型/图像占用2G内存后才会运行。如果您观察应用程序随时间变化的行为,您将看到大量运行过程中的高峰和低谷。我建议做两个实验

  • 启动任务管理器,在空闲状态下运行进程几秒钟,然后从服务器发送大量数据,以便请求处理100-1000次,然后让它保持打开状态几秒钟,然后关闭它。内存使用应恢复到应用打开前的状态

  • 遵循几乎相同的过程,但这次在处理请求后调用垃圾收集器(GC.Collect())。检查您这次的内存使用情况是否有所不同

  • 如果这不符合预期,请尝试创建并销毁TCP服务器类。内存使用应恢复正常。这会将问题隔离到您的类或垃圾收集器。

    4.7KB(您是说MB吗?)的已用内存并不能说明什么,因为GC可能会认为不值得运行收集。您可以尝试手动添加
    GC.Collect()
    调用并查看内存是否已释放,但您最好对应用程序进行评测,并查看是否有任何对象在手动强制收集后不再使用(它们的引用树一直到应用程序根目录)。