昨天我遇到了一个非常奇怪的错误,一天后我几乎没有任何进展,所以我想这是询问社区的好人选。我会要求一些patiecne,因为我认为这是一个虽然。
我有一个 C# Winforms 应用程序,在生产中单击几下后就会挂起。仅在生产环境中,开发环境中永远不会发生同样的情况。当挂起发生时,实际上什么也没有发生(没有错误消息,但是根据任务管理器,任务进入“无响应”状态)但 GUI 变得无响应。我在相同的环境中尝试过,我可以确认行为。
不幸的是,无法在 prod 环境中安装开发工具和调试应用程序。我能做的最好的事情就是在应用程序停止时从应用程序中进行内存转储。问题是我完全不明白我在故障转储中看到的内容:我的主线程(GUI 线程)似乎卡在我找不到任何原因的指令中。
这是我的主线程的堆栈跟踪:
KERNELBASE.dll!_RaiseException@16() + 0x54 bytes
[External Code]
CFAPControlLibrary.dll!CFAPControlLibrary.Communication.Base.GetSetting(string settingName) Line 850 + 0x10 bytes C#
CFAPControlLibrary.dll!CFAPControlLibrary.ConfigHelper.Get<CFAPControlLibrary.DataTypes.ActionSortingOption>(string settingName) Line 25 + 0x35 bytes C#
CFAPControlLibrary.dll!CFAPControlLibrary.ConfigHelper.Get<CFAPControlLibrary.DataTypes.ActionSortingOption>(string settingName, CFAPControlLibrary.DataTypes.ActionSortingOption defaultVal) Line 15 + 0x9 bytes C# CFAPControlLibrary.dll!CFAPControlLibrary.DataTypes.ActionStorage.Sort(System.Collections.Generic.List<CFAPControlLibrary.DataTypes.ActionClass> subject) Line 167 + 0xe bytes C#
CFAPControlLibrary.dll!CFAPControlLibrary.DataTypes.ActionStorage.GetByStatus(string pStatus) Line 162 + 0x46 bytes C#
CFAPControlLibrary.dll!CFAPControlLibrary.ActionSelector.FillNodes() Line 48 + 0x26 bytes C#
CFAPControlLibrary.dll!CFAPControlLibrary.CFAPMain.OnActionDetailsArrived(CFAPControlLibrary.CFAPMain.RawActionDetails bwr) Line 371 + 0x10 bytes C#
CFAPControlLibrary.dll!CFAPControlLibrary.CFAPMain.OnGetDetailsCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) Line 337 + 0xb bytes C#
user32.dll!_InternalCallWinProc@20() + 0x23 bytes
user32.dll!_UserCallWinProcCheckWow@32() + 0xb3 bytes
user32.dll!_DispatchMessageWorker@8() + 0xe6 bytes
user32.dll!_DispatchMessageW@4() + 0xf bytes
[External Code]
CFAPHost.exe!CFAPHost.Program.Main(string[] args) Line 50 + 0x1d bytes C#
[External Code]
mscoreei.dll!__CorExeMain@0() + 0x38 bytes
mscoree.dll!_ShellShim__CorExeMain@0() + 0x227 bytes
mscoree.dll!__CorExeMain_Exported@0() + 0x8 bytes
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
这里是我来自顶部堆栈帧的源代码: KernelBase.dll 的反汇编:
比我的代码中的最后一帧,m_SettingCache 是一个字典,它不包含请求的键:
我认为代码非常简单,它只是具有默认值的通用设置读取。如果出现问题(设置名称未定义或无法转换),将返回默认值。该代码肯定有效。我从转储中看到的是从字典中读取的内容永远不会返回,尽管它应该抛出 KeyNotFoundException 但这永远不会发生。有什么建议么?
注意:主线程确实在转储捕获的状态下停止:每次我进行转储时结果都是一样的。
注意2:在第一次执行此代码路径时不会发生挂起,在每种情况下,在挂起之前都会执行相同的代码路径(从应用程序日志中推断)
我将根据要求提供更多详细信息。提前致谢。
编辑:
CFAPControlLibrary.dll 是应用程序的主要程序集。它包含窗口窗体及其相应的逻辑。与服务器的通信是通过 WCF 实现的。更大的请求是在使用 BackgroundWorker 的并行线程中发出的。您在调用堆栈中看到的执行路径是由此类 BackgroundWorker 的完成事件调用的。
我在这里粘贴了请求的代码位
我的 AppDomain.CurrentDomain.UnhandledException 处理程序在这里
我首先认为无关紧要但后来证明很重要的堆栈部分(敏感的字符串文字已从图像中删除):
这表明 Application.Run 被调用,我不知道为什么它没有显示在调用堆栈中。
更新
在花了三天没有找到问题的原因后,我决定尝试一种解决方法。由于内存转储显示应用程序总是在同一点挂起:应该抛出 KeyNotFound 异常。最直接的解决方法是重构该代码以尽可能不抛出。该版本通过了测试并且从未挂起。这根本不是一个解决方案,但我们不能再花时间在这上面了。所以基本上我交叉手指发送代码,希望我再也不会看到这个崩溃。
谢谢大家的建议