【发布时间】:2011-10-21 14:40:43
【问题描述】:
我有一个 .NET Windows 服务的主要问题。它运行在具有非常不同配置的多台服务器上。该服务似乎容易在某些服务器上崩溃,但在其他服务器上稳定。最近引入了不稳定性,但到目前为止情况尚不清楚。我们有运行 Windows 2003 / Windows 2003 R2 / Windows 2008 的服务器。其中大部分都已完全更新。
我们尝试针对不同的目标框架版本 (2.0 / 3.5 / 4.0) 构建服务,但这并没有什么不同。具有不稳定服务的机器在每个版本的框架中都不稳定。我已经尝试修复 .NET 框架,但这也没有什么不同。据我所知,整个服务及其依赖项都在托管代码中。
我还尝试在命令行版本中运行服务器代码。这似乎运行稳定。我们现在将其用作解决方法。但是,问题与用户帐户无关。该服务通常作为“本地服务”运行。我试图让它在本地管理员帐户下运行,这是我用来运行命令行版本的帐户。但是服务仍然不稳定。
到目前为止,我已经能够在其中一台服务器上创建可重现的情况: - 在服务器上启动服务。 - 在同一服务器上的新 RDP 会话中以域用户身份登录。 - 启动我们的客户端软件,该软件在该会话中通过 TCP 远程访问我们的服务。 - 关闭客户端和会话。 - 与服务器上的域用户打开一个新的 RDP 会话。 - 服务瞬间崩溃!
请注意,当域用户登录到新的 RDP 会话时,服务会崩溃。那时我们的客户端软件还没有在那个会话中运行。如果我在第一次会话中不打开客户端并使用 TCP 远程访问服务,则该服务在第二次登录期间不会崩溃。如果我以本地管理员身份打开会话,服务也不会崩溃。
我已经能够将本机调试器 (OllyDbg) 附加到崩溃的服务。当尝试在地址 0x4bcdcee9 处执行时,它会因访问冲突而崩溃。该地址在所有服务器和配置上都是相同的(我每次都在事件日志中看到该地址)。我查看了崩溃线程的堆栈。该线程似乎是在崩溃之前创建的。首先它尝试加载 Ole32.dll。它从 Ole32 运行一些代码,然后我看到这些函数被调用:
- User32.SetTimer
- User32.GetMessageW
- User32.TranslateMessage
- User32.DispatchMessageW
崩溃发生在 DispatchMessageW 中。我可以在堆栈上看到 DispatchMessageW 的 *MSG 参数。好像这样通过了:
- hWnd = 0x00090082
- 消息 = 0x0000001e
- wParam = 0x00000000
- lParam = 0x00000000
我试过 Spy++。但它似乎没有在 Windows 服务中检测到任何 hWnd。
所以,服务接收到这个消息,尝试解析和分发它,每次都调用 0x4bc4cee9,这是未映射的内存,然后崩溃。
编辑:根据汉斯的建议,我调查了系统事件。我调试了服务。我在我的服务可执行文件中添加了一个额外的服务,这样我就可以启动辅助服务,然后附加一个调试器,然后启动真正的服务。这样,我什至可以调试服务的 OnStart。我在 SetWindowsHookA、SetWindowsHookW、SetWindowsHookExA 和 SetWindowsHookExW 上设置了断点,但没有一个被命中!?
编辑2:我检查了我所有的笔记,发现我跳到了错误的结论,因为我的笔记有错字:-S 无论如何,崩溃的地址是0x4bc4cee9。在执行的某个时刻,msado15.dll 会在那里加载。我可以看到,当客户端与服务器断开连接时,调试器中有 2 个托管异常。不久之后,我看到一条 WM_Timer 消息,它由调度程序处理并调用 CoFreeUnusedLibraries()。这将导致卸载 msado15.dll。我在反汇编程序中打开了 msado15.dll 并从 Microsoft 加载了符号。 DLL 是 Microsoft 数据访问组件 (MDAC) 2.8 SP1 的一部分。版本为2.82.4795.0,表示为最新版本,2011年1月发布。ADOConnection和ADORecordset有Advise()和Unadvise()函数。 Advise() 调用 InitAsyncEvents() 并调用 RegisterClassEx()。传递给 RegisterClassEx() 的 WndProc 是 FireEventOnMainThread(),它位于 0x4bc4cee9!我可以看到那里的功能!应该发生的是,当对象被释放时,应该调用 Unadvise() 和 DestroyAsyncEvents() 和 UnregisterClassEx()。但不知何故,这并没有发生。 DLL 在取消注册类之前被卸载。这会导致下一个事件发生崩溃。这可能与 2 个托管异常有关。我会进一步调查。
堆栈跟踪:http://pastebin.com/dsSjMe4Y
日志:http://pastebin.com/qD2MXvHd
我非常感谢您在这件事上的一些指导。比如,哪个进程可以发送这个消息?服务怎么可能完全错误地发送这个?如何避免这种情况?
谢谢你, 希斯克利夫
【问题讨论】:
-
很长的问题,大部分信息都是有用的。有用的是在崩溃和异常信息时有一个调用堆栈。确保您已正确加载符号。
-
WM_TIMECHANGE 是广播消息。转到所有顶级窗口。听起来你曾经有一个,然后带有窗口过程的 DLL 被卸载而没有很好地关闭窗口。 .NET 中的 SystemEvents 顺便说一句,需要显式取消注册的静态事件。
-
@SevaTitov 我添加了一个堆栈跟踪。所有其他信息似乎与我有关。
-
@HansPassant 非常感谢您提供的信息!这对我来说似乎是合理的。但我在过去 2 天里试图确认它,但我没有成功。我在开篇文章中添加了更多信息。希望您能进一步帮助我。
标签: .net windows-services crash