异步套接字高内存使用率和可能的泄漏

Async Socket High Memory Usage and Possible Leak

我正在重写服务器应用程序,对应用程序的内存使用感到困惑。早期版本是用 TcpListener 编写的,而新版本是普通的旧版本 Socket。这主要是出于性能和稳定性的原因,这些原因对于这个问题甚至这个问题都是次要的。

如前所述,所有内容都与 AcceptAsyncSendAsyncReceiveAsync 高度异步。最重要的是,我将 ThreadPool.QueueUserWorkItem 用于实用程序任务,例如 AcceptAsync 的初始启动并保持下一个 AcceptAsync 排队,处理后的调用写回 Socket,并调用清理断开连接的客户端。此外,我用 BeginInvokeEndInvoke.

触发了一系列事件

这些断开连接的检测以及数据可用性的主要驱动程序由我称之为 AvailabilityNotifier 的自定义 class 处理,它在 ReceiveAsync 上达到峰值并检测SocketAsyncEventArgs.BytesTransferred 为零会触发 Disconnect 事件。

应用程序的吞吐量很好,并且由于 System.Collections.Concurrent 对象的健康使用,锁争用几乎为零(相对而言)。但是,它会像捕食者紧贴猎物一样紧贴记忆。

我已经调试以验证我的内部集合正在被清除,客户端套接字正在关闭和处理,并使用缓冲池而不是为每次读取创建新的缓冲区。 运行 最终执行 1,000 个连接(100 个并发)和 sends/receives 100,000 条消息的测试应用程序使服务器进程内存膨胀到大约 800 MB,即使在 Windows 清除任何 TIME_WAITs 这可能已经发生了。由于大量 ObjectDisposedException 和空异常 catch 块,您可以在下面的链接 github 中看到,我确信 diposal 代码正在触发。

我说的都是没有引用的代码,因为这里的 post 太长了,所以这里是 github:https://github.com/hoagsie/TcpServerProgram.csClientProgram.cs 如果您想自己 运行 也提供,但主要操作在 NetworkServer.csAvailabilityNotifier.cs 中。我的示例服务器 运行ning 也有一个与之通信的 WCF 服务,但它只是标准的 WCF 项目,几乎没有任何修改。我只需要它来匹配示例场景。

我也不确定它在某种程度上是否重要,但我确实在 x64 模式下构建它而不是 AnyCPU/x86。这主要是为了在目标服务器上进行资源消耗机会,但我没有注意到 x86 或 x64 中关于此问题的行为差异。

编辑:

一位同事在 Visual Studio 中指出了快照工具。我以前从未见过这个,它显示的内容与我一直使用的 dotTrace 不同。它指向围绕 SocketAsyncEventArgs 对象的大量分配,这是有道理的,但它们一直在构建和构建。我再次查看它的成员列表,发现它有一个 Dispose 方法。我的问题已经消失了。我没有意识到那是一个 IDisposable 对象。

一位同事在 Visual Studio 中指出了快照工具。我以前从未见过这个,它显示的内容与我一直使用的 dotTrace 不同。它指向围绕 SocketAsyncEventArgs 对象的大量分配,这是有道理的,但它们一直在构建和构建。我再次查看它的成员列表,发现它有一个 Dispose 方法。我的问题已经消失了。我没有意识到这是一个 IDisposable 对象。