为啥 .NET 应用程序会停止执行任何网络 I/O?

Posted

技术标签:

【中文标题】为啥 .NET 应用程序会停止执行任何网络 I/O?【英文标题】:Why would a .NET app stop being able to perform any network I/O?为什么 .NET 应用程序会停止执行任何网络 I/O? 【发布时间】:2013-03-12 20:40:30 【问题描述】:

我正在调查在客户端工作站上看到的一个问题,其中相当大的 WinForms .NET 3.5 应用程序偶尔会停止执行任何类型的网络操作,并最终由于在主线程。

我所说的网络操作是指任何需要新网络连接的东西。该应用程序连接到多个 Oracle 数据库和 SOAP Web 服务。

检查应用程序的内存转储会显示在不同线程上对非托管代码的各种阻塞调用:

DNS 查找卡住 (System.Net.UnsafeNclNativeMethods+SafeNetHandlesXPOrLater.getaddrinfo)

Open Sockets 卡住 (System.Net.UnsafeNclNativeMethods+OSSOCK.WSAConnect)

关闭套接字卡住 (System.Net.UnsafeNclNativeMethods+SafeNetHandles.closesocket)

打开 ODBC 卡住 (System.Data.Common.UnsafeNativeMethods.SQLDriverConnectW)

上述所有非托管堆栈的顶部如下所示:

0a90df4c 77858cd8 ntdll!ZwWaitForSingleObject+0x15
0a90df74 73c5716f ntdll!RtlIntegerToUnicodeString+0x20b
0a90dfbc 76f45db1 siifslsp!WSPStartup+0x483f

重启应用后,恢复正常。这向我暗示了某种类型的资源泄漏,但我该如何追踪呢?

我检查了开放网络连接的实例,可以看到以下计数:

System.Net.HttpWebRequest 5 个实例 System.Net.Sockets.Socket 11 个实例 System.Data.Odbc.OdbcConnectionHandle 4 个实例

这些在我看来并不高。

更新 1 - !FinalizeQueue 的截断输出

!FinalizeQueue 的输出对我来说没有任何异常。我已将其限制为任何与 IO 相关的内容。

0:024> !FinalizeQueue
SyncBlocks to be cleaned up: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 359 finalizable objects (41f35654->41f35bf0)
generation 1 has 0 finalizable objects (41f35654->41f35654)
generation 2 has 10697 finalizable objects (41f2af30->41f35654)
Ready for finalization 0 objects (41f35bf0->41f35bf0)
Statistics:
      MT    Count    TotalSize Class Name
6e612a38        1           20 System.Net.SafeLocalFree
6ea7e550        1           24 System.Net.Sockets.TcpClient
6a606c54        1           24 System.Data.Odbc.OdbcEnvironmentHandle
6e60f7f4        2           40 System.Net.SafeFreeAddrInfo
05da845c        2           40 System.Net.SafeCloseSocket+InnerSafeCloseSocket
0642c010        2           56 System.Net.SafeCloseSocketAndEvent
6e6106bc        4           96 System.Net.SafeRegistryHandle
6e6105d0        4          112 System.Net.SafeCloseSocketAndEvent
6a6069bc        4          112 System.Data.Odbc.OdbcConnectionHandle
6a6060c8        4          256 System.Data.Odbc.OdbcConnection
6e60f764       11          264 System.Net.SafeCloseSocket
6e6115cc        7          336 System.Net.Sockets.NetworkStream
66e60eeec       11          836 System.Net.Sockets.Socket

Total 11056 objects

更新 2 - 使用 !locks!critsec 查看块的位置

!critsec 的输出是:

0:002> !critsec 73c7147c

CritSec siifslsp!GetLspGuid+1a0fc at 73c7147c
WaiterWoken        No
LockCount          8
RecursionCount     1
OwningThread       5f24
EntryCount         0
ContentionCount    8
*** Locked

不确定5f24 指的是什么。 !Threads 的输出没有显示任何具有OSID5f24 的线程。

【问题讨论】:

【参考方案1】:

我承认我没有明确的答案,但这里有一些建议。

首先,按照this blog post 中的说明,使用WinDbg 中的!waitlist 命令尝试找出线程阻塞的原因。这可能会抛出一个线索,解释为什么不同的线程会阻塞。

Here's another handy blog post 解释了如何深入挖掘以找到阻塞线程的原因。

另一个好的信息来源可能是Event Viewer,特别是the Windows Logs -> System 部分。您可以扫描此处的条目并查找任何 ErrorWarnings 并查看他们所说的内容。那里可能会发布与网络相关的消息,你永远不知道。

我会不断更新此答案,因为我会发现其他可能对您有用的信息。

【讨论】:

siifslsp 是与已卸载的应用程序关联的 WinSock LSP。删除 WinSock LSP 解决了问题。 @Iain 很高兴你解决了这个问题。我的回答是否对您有所帮助,我不确定 WinSock LSP 是什么以及您如何发现它与已卸载的应用程序相关联。听起来很深:) 说来话长,但您的回答启发了我深入研究非托管代码。从我回答的更新 2 开始,我使用命令 lmv m siifslsp 来识别 siifslsp DLL,一些谷歌搜索告诉我,“GetLspGuid”方法是您在 WinSock LSP 上找到的。我得到了 DLL 并在记事本中打开它以搜索任何可能暗示其来源的字符串。我找到了供应商并最终找到了它所属的软件,用户认为该软件是他最近从机器中删除的东西,因为它给他带来了问题。案件结案。 我并不真正了解 LSP 的详细信息,但我回忆起几年前在计算机上遇到的问题,即损坏的 WinSock 堆栈会阻止网络发生。通常是因为应用程序将它自己的不可靠插件(LSP?)插入到 WinSock 堆栈中【参考方案2】:

.NET 默认将远程连接数限制为 2。

确保正确设置了以下属性:

<system.net>
  <connectionManagement>
    <add address = "*" maxconnection = "24" />
  </connectionManagement>
</system.net>

查看以下 MSDN 页面了解更多信息:

http://msdn.microsoft.com/en-gb/library/system.net.configuration.connectionmanagementelement.maxconnection(v=vs.100).aspx

【讨论】:

以上是关于为啥 .NET 应用程序会停止执行任何网络 I/O?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 .NET 应用程序从网络驱动器运行时会崩溃?

php为啥会自动停止执行

FFMPEG I/O 的自定义读取功能

为啥这个 CMD .bat 文件会停止?

为啥 Visual Studio 不调试我的 VB.NET 应用程序?

C# 为啥定时器会自动停止