如何在.net内存转储中列出正在运行的任务

时间:2017-06-01 15:22:55

标签: .net multithreading asynchronous windbg sos

我们有一个使用async / await模式的复杂ASP.Net Core应用程序。应用程序最近停止响应,我们为它进行了内存转储。我们怀疑有一些异步操作会导致应用程序卡住,但不确定是哪一个。在为Web应用程序进行内存转储后,我们可以看到很少的运行线程,因为由于使用了async / await,线程被返回到线程池。 问题是,是否可以在内存转储中列出正在运行的任务,以及它们运行的​​位置,以便我可以判断哪个异步操作会使应用程序卡住?对于同步阻塞调用,它很容易 - 只列出所有活动线程的调用堆栈。但是对于异步操作,它不再起作用了。 (添加更多跟踪是一种可能的方法,但情况是我们无法保证我们在应用程序及其依赖库中的每个异步操作都有足够的跟踪。)

例如,如果ASP.Net Core应用程序卡在某些类似的代码中,我如何从内存转储中告诉它?

public async Task SomeBadMethodInADependentLibrary()
{
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
    await tcs.Task;
}

1 个答案:

答案 0 :(得分:9)

您当然可以在堆中找到任务对象,并使用SOS命令手动开始分析它们,例如:就像这个调试会话的开始一样:

0:013> !dumpheap -stat -type Task
Statistics:
      MT    Count    TotalSize Class Name
[...]
71e03f28        4          160 System.Threading.Tasks.Task
Total 28 objects

0:013> !dumpheap -mt 71e03f28 
 Address       MT     Size
022bd900 71e03f28       40       
[...]

0:013> !do 022bd900
Name:        System.Threading.Tasks.Task
MethodTable: 71e03f28
EEClass:     719cd6e0
Size:        40(0x28) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
71df1638  40019cd       1c         System.Int32  1 instance        3 m_taskId
71defb44  40019ce        4        System.Object  0 instance 022bd8e0 m_action
[...]

0:013> !DumpObj 022bd8e0
Name:        System.Action
MethodTable: 71e0588c
EEClass:     719357b8
Size:        32(0x20) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
71defb44  40002b5        4        System.Object  0 instance 022bd8e0 _target
71defb44  40002b6        8        System.Object  0 instance 00000000 _methodBase
71df2bdc  40002b7        c        System.IntPtr  1 instance  4b00e64 _methodPtr
71df2bdc  40002b8       10        System.IntPtr  1 instance   4e0c30 _methodPtrAux
[...]

0:013> !u 4e0c30 
Unmanaged code
004e0c30 e833df8372      call    clr!PrecodeFixupThunk (72d1eb68)
[...]

现在它开始变得麻烦......

从我的观点来看,最方便的方法(在WinDbg中)是使用Mex (Github)!TaskTriage命令:

0:013> !TaskTriage
Normal Mode - not showing successful Tasks
Address    Target     Status                        Method                             Exceptions
==================================================================================================
022bd900 | 022bd8e0 | TASK_STATE_DELEGATE_INVOKED | Demo.Program.printMessage()     |     <none>
022bd974 | 022bd868 | TASK_STATE_DELEGATE_INVOKED | Demo.Program+<>c.<Main>b__0_0() |     <none>
022bd9bc | 022bd868 | TASK_STATE_STARTED          | Demo.Program+<>c.<Main>b__0_1() |     <none>
022bda04 | 022bd868 | TASK_STATE_STARTED          | Demo.Program+<>c.<Main>b__0_2() |     <none>
==================================================================================================
Address    Target     Status                        Method                             Exceptions

在Visual Studio上使用WinDbg的想法很好,因为VS2015和VS2017都无法从转储文件中提供相同的结果:

Result in VS2015 and VS2017