我的.NET Windows服務存在一個主要問題。它運行在配置完全不同的多臺服務器上。該服務似乎易受某些服務器上的崩潰影響,但在其他服務器上保持穩定。最近引入了不穩定性,但迄今爲止條件未知。我們有運行Windows 2003/Windows 2003 R2/Windows 2008的服務器。它們中的大多數都已完全更新。.NET Windows服務在調度Windows消息時崩潰
我們試着針對不同的目標框架版本(2.0/3.5/4.0)構建服務,但它沒有什麼區別。對於每個版本的框架,具有不穩定服務的機器都不穩定。我試過修復.NET框架,但這也沒有什麼不同。據我所知,整個服務及其依賴關係都在託管代碼中。
我也嘗試在命令行版本中運行服務器代碼。這似乎運行穩定。我們現在使用這個作爲解決方法。但是,該問題與用戶帳戶無關。該服務通常作爲「本地服務」運行。我試圖讓它在本地管理員帳戶下運行,這是我用來運行命令行版本的帳戶。但服務仍然不穩定。
到目前爲止,我已經能夠在其中一臺服務器上創建可重現的情況: - 在服務器上啓動服務。 - 作爲域用戶登錄到同一臺服務器上的新RDP會話中。 - 啓動我們的客戶端軟件,該軟件通過該會話中的TCP遠程訪問來訪問我們的服務。 - 關閉客戶端和會話。 - 在服務器上與域用戶打開一個新的RDP會話。 - 服務即時崩潰!
請注意,服務在域用戶登錄到新的RDP會話時崩潰。當時我們的客戶端軟件尚未在該會話中運行。如果我在第一個會話中未打開客戶端並使用TCP遠程訪問服務,則該服務在第二次登錄期間不會崩潰。如果我以本地管理員身份打開會話,則該服務也不會崩潰。
我已經能夠將本機調試器(OllyDbg)附加到崩潰服務。嘗試在地址0x4bcdcee9處執行時,它會因訪問衝突而崩潰。該地址在所有服務器和配置上都是相同的(我在eventlog中每次都看到該地址)。我已經看過了崩潰線程的堆棧。該線程似乎是在崩潰之前創建的。首先它會嘗試加載Ole32.dll。它運行從OLE32一些代碼,然後我看到被稱爲以下功能:
- User32.SetTimer
- User32.GetMessageW
- User32.TranslateMessage
- User32.DispatchMessageW
崩潰在DispatchMessageW中。我可以在堆棧上看到DispatchMessageW的* MSG參數。它看起來像這樣被傳遞:
- 的hWnd = 0x00090082
- 消息= 0X0000001E
- 的wParam = 00000000
- 的lParam = 00000000
我試過間諜++。但它似乎沒有檢測到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 btw,需要明確註銷的靜態事件。 –
@SevaTitov我加了一個堆棧跟蹤。所有其他信息似乎與我有關。 – Heathcliff