c# – 使用Windbg在内存转储中查找调用的目标线程
背景
客户报告了C#应用程序中的挂起.我在应用程序挂起时有一个内存转储.内存转储显示主UI线程,显示进度表单和运行的多个后台线程.其中一个后台线程正在尝试Control.Invoke回到主线程来更新表单. CLR堆栈如下所示: System.Threading.WaitHandle.WaitOneNative(Microsoft.Win32.SafeHandles.SafeWaitHandle,UInt32,Boolean,Boolean) System.Threading.WaitHandle.WaitOne(Int64,Boolean) System.Threading.WaitHandle.WaitOne(Int32,Boolean) System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle) System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control,System.Delegate,System.Object[],Boolean) System.Windows.Forms.Control.Invoke(System.Delegate,System.Object[]) profdata.com.Library.frmAsyncExec.SetMessageText(System.String) profdata.com.Library.frmAsyncExec.SetMessage(System.String,System.String) profdata.com.Library.frmAsyncExec.DoAsyncProcess(System.Object) System.Threading.ThreadHelper.ThreadStart_Context(System.Object) System.Threading.ExecutionContext.runTryCode(System.Object) System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode,CleanupCode,System.Object) System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext,System.Threading.ContextCallback,System.Object) System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,System.Object) System.Threading.ThreadHelper.ThreadStart(System.Object) UI线程处于模态循环中并等待消息: System.Windows.Forms.UnsafeNativeMethods.WaitMessage() System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32,Int32,Int32) System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32,System.Windows.Forms.ApplicationContext) System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32,System.Windows.Forms.ApplicationContext) System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form) System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window) profdata.com.Library.frmAppletBaseForm.ShowDialog(System.Windows.Forms.IWin32Window) profdata.com.Library.frmAsyncExec.ExecuteProcess(System.Windows.Forms.IWin32Window) 我验证了消息队列中的唯一消息(我可以看到)是一个绘制消息.消息15对应于WM_PAINT: 0:000> !dso OS Thread Id: 0x126c (0) ESP/REG Object Name ebx 01a688d0 System.Windows.Forms.Application+ThreadContext esi 01a6eb9c System.Windows.Forms.Application+ComponentManager+ComponentHashtableEntry edi 1b0c05e0 System.Collections.Hashtable+HashtableEnumerator 0036e244 1b08430c System.Windows.Forms.NativeMethods+MSG[] 0:000> !da 1b08430c Name: System.Windows.Forms.NativeMethods+MSG[] MethodTable: 67e0592c EEClass: 67be89b8 Size: 40(0x28) bytes Array: Rank 1,Number of elements 1,Type VALUETYPE Element Methodtable: 67e059dc 0:000> !dumpvc 67e059dc 1b084314 Name: System.Windows.Forms.NativeMethods+MSG MethodTable 67e059dc EEClass: 67bbd880 Size: 36(0x24) bytes (C:WindowsassemblyGAC_MSILSystem.Windows.Forms2.0.0.0__b77a5c561934e089System.Windows.Forms.dll) Fields: MT Field Offset Type VT Attr Value Name 691b35f0 4002ba0 0 System.IntPtr 1 instance b02ee hwnd 691b2f74 4002ba1 4 System.Int32 1 instance 15 message 691b35f0 4002ba2 8 System.IntPtr 1 instance 0 wParam 691b35f0 4002ba3 c System.IntPtr 1 instance 0 lParam 691b2f74 4002ba4 10 System.Int32 1 instance 264314085 time 691b2f74 4002ba5 14 System.Int32 1 instance 188 pt_x 691b2f74 4002ba6 18 System.Int32 1 instance 386 pt_y 我知道Control.MarshaledInvoke是作为已知消息的PostMessage实现的: private object MarshaledInvoke(Control caller,Delegate method,object[] args,bool synchronous) { ... System.Windows.Forms.UnsafeNativeMethods.PostMessage(new HandleRef(this,this.Handle),threadCallbackMessage,IntPtr.Zero,IntPtr.Zero); ... } MSDN说这个约为PostMessage:
我怀疑这是后台线程访问UI对象的经典案例,已知该UI对象会导致应用程序挂起.我很清楚这是一件坏事. 由于有多个后台线程,我想确定哪个后台线程搞砸了. 题 是否可以使用内存转储中的信息确定对Control.Invoke的调用的目标线程? 工作到目前为止 我已经获得了后台线程的堆栈对象的转储: 0:000> ~20s 0:020> !dso OS Thread Id: 0x5d8 (20) ESP/REG Object Name ecx 01a2b2d0 System.Runtime.Remoting.Contexts.Context 0c42e49c 1b083e20 System.Threading.ManualResetEvent 0c42e524 01a2006c System.Collections.Hashtable 0c42e560 1b083e38 Microsoft.Win32.SafeHandles.SafeWaitHandle 0c42e5fc 1b044128 System.Windows.Forms.PropertyStore 0c42e608 1b060b68 System.Collections.Queue 0c42e610 1b083de0 System.Windows.Forms.Control+ThreadMethodEntry 0c42e65c 1b043b30 profdata.com.DailyReporting.frmDRAsyncExec 0c42e66c 1b083cb0 System.Object[] (System.Object[]) 0c42e670 1b083c90 profdata.com.Library.frmAsyncExec+SetMessageDelegate 0c42e674 1b083cc4 System.Windows.Forms.Control+MultithreadSafeCallScope 0c42e694 1b043b30 profdata.com.DailyReporting.frmDRAsyncExec 我已经尝试过在ThreadMethodEntry和Context对象上,但我不确定我在寻找什么: 0:020> !do 1b083de0 Name: System.Windows.Forms.Control+ThreadMethodEntry MethodTable: 67e05380 EEClass: 67be8454 Size: 52(0x34) bytes (C:WindowsassemblyGAC_MSILSystem.Windows.Forms2.0.0.0__b77a5c561934e089System.Windows.Forms.dll) Fields: MT Field Offset Type VT Attr Value Name 67dff750 40011b9 4 ...ows.Forms.Control 0 instance 1b043b30 caller 67dff750 40011ba 8 ...ows.Forms.Control 0 instance 1b043b30 marshaler 691b118c 40011bb c System.Delegate 0 instance 1b083c90 method 691844f8 40011bc 10 System.Object[] 0 instance 1b083cb0 args 691b0944 40011bd 14 System.Object 0 instance 00000000 retVal 691b0ebc 40011be 18 System.Exception 0 instance 00000000 exception 691847f4 40011bf 2c System.Boolean 1 instance 1 synchronous 691847f4 40011c0 2d System.Boolean 1 instance 0 isCompleted 69197b54 40011c1 1c ....ManualResetEvent 0 instance 1b083e20 resetEvent 691b0944 40011c2 20 System.Object 0 instance 1b083e14 invokeSyncObject 691ada1c 40011c3 24 ....ExecutionContext 0 instance 1b083cd0 executionContext 691aa00c 40011c4 28 ...ronizationContext 0 instance 00000000 syncContext 0:020> !do 01a2b2d0 Name: System.Runtime.Remoting.Contexts.Context MethodTable: 691a210c EEClass: 68fcf620 Size: 60(0x3c) bytes (C:WindowsassemblyGAC_32mscorlib2.0.0.0__b77a5c561934e089mscorlib.dll) Fields: MT Field Offset Type VT Attr Value Name 691844f8 4001f60 4 System.Object[] 0 instance 01a2b3a0 _ctxProps 691a219c 4001f61 8 ...micPropertyHolder 0 instance 00000000 _dphCtx 691a75b4 4001f62 c ...em.LocalDataStore 0 instance 00000000 _localDataStore 69196f18 4001f63 10 ...ging.IMessageSink 0 instance 00000000 _serverContextChain 69196f18 4001f64 14 ...ging.IMessageSink 0 instance 00000000 _clientContextChain 691b1508 4001f65 18 System.AppDomain 0 instance 01a01298 _appDomain 691844f8 4001f66 1c System.Object[] 0 instance 00000000 _ctxStatics 691b35f0 4001f67 20 System.IntPtr 1 instance 551520 _internalContext 691b2f74 4001f68 24 System.Int32 1 instance 0 _ctxID 691b2f74 4001f69 28 System.Int32 1 instance 3 _ctxFlags 691b2f74 4001f6a 2c System.Int32 1 instance 1 _numCtxProps 691b2f74 4001f6b 30 System.Int32 1 instance 0 _ctxStaticsCurrentBucket 691b2f74 4001f6c 34 System.Int32 1 instance 0 _ctxStaticsFreeIndex 691a219c 4001f6d 654 ...micPropertyHolder 0 shared static _dphGlobal >> Domain:Value 00557ff8:01a2b068 << 69189944 4001f6e 658 ...LocalDataStoreMgr 0 shared static _localDataStoreMgr >> Domain:Value 00557ff8:01a2b07c << 691b2f74 4001f6f b40 System.Int32 1 shared static _ctxIDCounter >> Domain:Value 00557ff8:0 << 或者可能有更原生的方法涉及找到窗口句柄与特定线程的关联,但如果是这样,我不知道该怎么做. 解决方法
您需要在ThreadMethodEntry中转储在UI线程上执行的委托(方法字段).其他成员只在那里,以便UI线程知道发送回调的控件以及执行它的同步上下文.
还有一些标志可以检查是否有必要进行调用,如果调用失败则还有一个异常字段,如果通过Invoke调用完成,则可以编组回调用者.你可以安全地忽略那里的其他东西. 更多信息如何找到当您在此处找到代理实例时调用的方法:http://geekswithblogs.net/akraus1/archive/2012/05/20/149699.aspx 由于您的回调甚至没有执行,您还应该查看其他线程.这种神秘的挂??起通常与WM_SETTING_CHANGE窗口消息一起发生,其中非UI线程试图调用您的控件(参见http://ikriv.com/dev/dotnet/MysteriousHang.html#BeginInvokeDance). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |