我正在重写服务器应用程序,并且对应用程序的内存使用情况感到困惑。早期版本使用TcpListener
编写,而新版本使用Socket
。这主要是出于性能和稳定性的原因,这个问题仅次于这个问题甚至是这个问题。
如前所述,AcceptAsync
,SendAsync
和ReceiveAsync
的所有内容都非常异步。最重要的是,我使用ThreadPool.QueueUserWorkItem
来执行实用程序任务,例如AcceptAsync
的初始启动并保持下一个AcceptAsync
排队,处理后的调用将写回Socket
1}},并且调用清理断开连接的客户端。此外,我还会使用BeginInvoke
和EndInvoke
触发一系列事件。
对这些断开连接以及数据可用性的主要驱动程序的检测由我调用AvailabilityNotifier
的自定义类处理,该类在ReceiveAsync
上达到峰值并检测到SocketAsyncEventArgs.BytesTransferred
为零会触发Disconnect
事件。
应用程序的吞吐量很好,并且由于System.Collections.Concurrent
对象的健康使用,几乎为零(相对而言)锁争用。然而,它依附于记忆中,就像一只捕食者一样紧紧抓住了。
我已经调试以验证我的内部集合是否已被清除,客户端套接字正在被关闭和处理,并利用缓冲池而不是为每次读取创建新的缓冲区。运行最终执行1,000个连接(100个并发)并发送/接收100,000个消息的测试应用程序会使服务器进程内存膨胀到大约800 MB,即使Windows清除了可能发生的任何TIME_WAIT
,它也永远不会停止运行。我知道,由于你可以在下面链接的github中看到大量的ObjectDisposedException
和null异常catch
块,所以偶像代码会被触发。
我说没有引用代码的所有内容因为这里的帖子很长,所以这里有一个github:https://github.com/hoagsie/TcpServer。如果您想自己运行Program.cs
和ClientProgram.cs
,则会提供NetworkServer.cs
和AvailabilityNotifier.cs
,但主要操作位于SocketAsyncEventArgs
和Dispose
。我运行的示例服务器也有一个与之对话的WCF服务,但它只是标准的WCF项目,几乎没有任何修改。我只是需要它来匹配一个示例场景。
我也不确定它在某种程度上是否重要,但我确实在x64模式而不是AnyCPU / x86中构建它。这主要是针对目标服务器上的资源消耗机会,但我没有注意到x86或x64中与此问题有关的行为差异。
修改
一位同事在Visual Studio中指出了快照工具。我之前从未见过它,它显示的东西与我使用的东西不同,这是dotTrace。它指出围绕IDisposable
对象的大量分配是有道理的,但他们不断建造和建造。我再次查看了其成员列表,发现它有一个customer
方法。我的问题已经消失了。我没有意识到这是一个customer_membership_status
对象。
答案 0 :(得分:0)
一位同事在Visual Studio中指出了快照工具。我之前从未见过它,它显示的东西与我使用的东西不同,这是dotTrace。它指出围绕SocketAsyncEventArgs
对象的大量分配是有道理的,但他们不断建造和建造。我再次查看了其成员列表,发现它有一个Dispose
方法。我的问题已经消失了。我没有意识到这是一个IDisposable
对象。