使用dotnet-dump分析dotnet转储文件
有很多时候,在生产环境会产生各种各样的问题,但在生成环境计划是不能调试的,所以dotnet-dump这时就启动作用了。
除了dotnet-dump外,windows下windbg,linux下的lldb是更为强大的分析工具。
微软的文档:
https://docs.microsoft.com/zh-cn/dotnet/core/diagnostics/dotnet-dump
开始使用dotnet-dump
假设一种情况,在生成环境中线程数高,且内存溢出。
public IActionResult Index() { _logger.LogInformation("新增一条线程。"); Task.Run(() => { // 添加1Mb。 while (true) { _logger.LogInformation("添加1Mb"); var buff = new byte[1024 * 1024]; for (int i = 0; i < buff.Length; i++) { buff[i] = 0; } _byteBag.Add(buff); SpinWait.SpinUntil(() => false, 10000); } }); return View(); }
以上简单的设置一下,然后浏览器多刷几次。
每刷新一次,则线程数加1,要知道系统有线程数限制,超过极限后会爆炸。
使用dotnet-dump分析
第一步收集转储文件
dotnet-dump collect -p 10504 -o dump
第二部分析转储文件
dotnet-dump analyze dump
分析:
> clrthreads ThreadCount: 39 UnstartedThread: 0 BackgroundThread: 38 PendingThread: 0 DeadThread: 0 Hosted Runtime: no Lock DBG ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception 20 1 1f34 000001BE985BEF50 202a020 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 MTA 32 2 32dc 000001C3A69D50D0 2b220 Preemptive 000001C258931410:000001C258931668 000001BE96B95A10 0 MTA (Finalizer) 27 3 2488 000001C3A6A0F500 102a220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 MTA (Threadpool Worker) 52 7 4b90 000001C3A6BEF8F0 202b220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 MTA 29 14 29e4 000001C3A7286CB0 3029220 Preemptive 000001BFD8936AE8:000001BFD89389C0 000001BE96B95A10 0 MTA (Threadpool Worker) 41 16 3c38 000001C3A7286010 3029220 Preemptive 000001C0989349E0:000001C098934BE8 000001BE96B95A10 0 MTA (Threadpool Worker) 1 18 798 000001C3A7401180 3029220 Preemptive 000001C0589317B8:000001C058931CF8 000001BE96B95A10 0 MTA (Threadpool Worker) 58 19 4ee0 000001C3A73FD260 3029220 Preemptive 000001BF58931900:000001BF58931AC8 000001BE96B95A10 0 MTA (Threadpool Worker) 11 20 1594 000001C3A73FF1F0 3029220 Preemptive 000001C2189324A0:000001C218932738 000001BE96B95A10 0 MTA (Threadpool Worker) 9 21 12c0 000001C3A74004E0 3029220 Preemptive 000001C118931A60:000001C118931AC0 000001BE96B95A10 0 MTA (Threadpool Worker) 17 22 1a44 000001C3A73FBF70 3029220 Preemptive 000001BED8931938:000001BED8931970 000001BE96B95A10 0 MTA (Threadpool Worker) 53 23 4d0c 000001C3A73FCC10 3029220 Preemptive 000001C258932770:000001C258932B10 000001BE96B95A10 0 MTA (Threadpool Worker) 12 24 1648 000001C3A73FD8B0 3029220 Preemptive 000001BFD8934BF8:000001BFD89369C0 000001BE96B95A10 0 MTA (Threadpool Worker) 55 25 4d4c 000001C3A73FC5C0 3029220 Preemptive 000001BE98932F40:000001BE98933590 000001BE96B95A10 0 MTA (Threadpool Worker) 31 26 2ff0 000001C3A73FFE90 3029220 Preemptive 000001BF18933560:000001BF18933578 000001BE96B95A10 0 MTA (Threadpool Worker) 7 27 11b0 000001C3A73FEBA0 3029220 Preemptive 000001C198932150:000001C198932510 000001BE96B95A10 0 MTA (Threadpool Worker) 59 28 4fc0 000001C3A73FDF00 3029220 Preemptive 000001C218933848:000001C218935258 000001BE96B95A10 0 MTA (Threadpool Worker) 35 29 35bc 000001C3A73FE550 3029220 Preemptive 000001C2189330D8:000001C2189331D0 000001BE96B95A10 0 MTA (Threadpool Worker) 10 30 12dc 000001C3A73FF840 3029220 Preemptive 000001BF98931900:000001BF98932140 000001BE96B95A10 0 MTA (Threadpool Worker) 34 33 34fc 000001C3A73F9FE0 3029220 Preemptive 000001BFD8932FB0:000001BFD89349C0 000001BE96B95A10 0 MTA (Threadpool Worker) 56 15 4da4 000001C3A73FA630 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 6 35 ef8 000001C3A73FAC80 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 50 36 492c 000001C3A73FB920 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 21 37 2048 000001C3A7285370 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 13 38 18f0 000001C3A6C23470 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 40 39 3ac8 000001C3A6C22E20 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 15 40 1974 000001C3A6C23AC0 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 8 41 1200 000001C3A6C24110 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 4 42 a94 000001C3A6C22180 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 43 43 4220 000001C3A6C227D0 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 26 44 2480 000001C3A6C24760 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 30 45 2d1c 000001C3A6C21B30 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 33 46 3498 000001C3A6C24DB0 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 5 47 bd8 000001C3A6C25400 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 38 48 3610 000001C3A76DC0C0 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 18 49 1da0 000001C3A76DB420 21220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 Ukn 36 34 35d0 000001C3A76DADD0 8029220 Preemptive 000001C058932268:000001C058933CF8 000001BE96B95A10 0 MTA (Threadpool Completion Port) 49 31 4778 000001C3A76D9AE0 1029220 Preemptive 000001C1D8938958:000001C1D8938C38 000001BE96B95A10 0 MTA (Threadpool Worker) 14 32 1904 000001C3A76D6860 8029220 Preemptive 0000000000000000:0000000000000000 000001BE96B95A10 0 MTA (Threa
分析线程
49 31 4778 000001C3A76D9AE0 1029220 Preemptive 000001C1D8938958:000001C1D8938C38 000001BE96B95A10 0 MTA (Threadpool Worker)
> setthread 31 > clrstack OS Thread Id: 0x2ff0 (31) Child SP IP Call Site 000000AEC14FE0A8 00007ffd1ee8c414 [HelperMethodFrame: 000000aec14fe0a8] System.Threading.Thread.SleepInternal(Int32) 000000AEC14FE1A0 00007FFC6C1438CD System.Threading.SpinWait.SpinOnceCore(Int32) 000000AEC14FE250 00007FFC6C1811E7 System.Threading.SpinWait.SpinUntil(System.Func`1<Boolean>, Int32) 000000AEC14FE2A0 00007FFC6BF23560 DotnetDump.Controllers.HomeController.<Index>b__3_0() [E:\Test\DotnetDump\Controllers\HomeController.cs @ 40] 000000AEC14FE340 00007FFCCAB2C01F System.Threading.Tasks.Task`1[[System.__Canon, System.Private.CoreLib]].InnerInvoke() 000000AEC14FE380 00007FFCCAA38092 System.Threading.Tasks.Task+<>c.<.cctor>b__274_0(System.Object) 000000AEC14FE3B0 00007FFCCAA38012 System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 000000AEC14FE400 00007FFCCAA37CE7 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread) 000000AEC14FE4A0 00007FFCCAA37BC3 System.Threading.Tasks.Task.ExecuteEntryUnsafe(System.Threading.Thread) 000000AEC14FE4E0 00007FFCCAA37B5B System.Threading.Tasks.Task.ExecuteFromThreadPool(System.Threading.Thread) 000000AEC14FE510 00007FFC6C149BF1 System.Threading.ThreadPoolWorkQueue.Dispatch() 000000AEC14FE990 00007ffccb0b6ba3 [DebuggerU2MCatchHandlerFrame: 000000aec14fe990]
通过此方法分析线程调用栈。由于有pdb文件,因此可以很方便的看到具体的错误信息。
使用clrsatck -a
找到
000000AEC14FE2A0 00007FFC6BF23560 DotnetDump.Controllers.HomeController.<Index>b__3_0() [E:\Test\DotnetDump\Controllers\HomeController.cs @ 40] PARAMETERS: this (0x000000AEC14FE340) = 0x000001c0589e6a40 LOCALS: 0x000000AEC14FE318 = 0x000001c2dc831e00 0x000000AEC14FE314 = 0x0000000000100000 0x000000AEC14FE310 = 0x0000000000000000 0x000000AEC14FE30C = 0x0000000000000001
> dumpobj 0x000001c0589e6a40 Name: DotnetDump.Controllers.HomeController MethodTable: 00007ffc6bd80058 EEClass: 00007ffc6bd73968 Size: 104(0x68) bytes File: E:\Test\DotnetDump\bin\Debug\netcoreapp3.1\DotnetDump.dll Fields: MT Field Offset Type VT Attr Value Name 00007ffc6bd9dd98 400005c 8 ...ControllerContext 0 instance 000001c0589e6508 _controllerContext 00007ffc6b9a69a8 400005d 10 ...lMetadataProvider 0 instance 0000000000000000 _metadataProvider 00007ffc6b9a8130 400005e 18 ...odelBinderFactory 0 instance 0000000000000000 _modelBinderFactory 00007ffc6b9a83e0 400005f 20 ...ectModelValidator 0 instance 0000000000000000 _objectValidator 00007ffc6bd9dea0 4000060 28 ...re.Mvc.IUrlHelper 0 instance 0000000000000000 _url 00007ffc6b9ae310 4000061 30 ...lemDetailsFactory 0 instance 0000000000000000 _problemDetailsFactory 00007ffc6bd9d0c8 400001e 38 ...empDataDictionary 0 instance 000001c0589e7100 _tempData 0000000000000000 400001f 40 ...s.DynamicViewData 0 instance 0000000000000000 _viewBag 00007ffc6bd9cf18 4000020 48 ...iewDataDictionary 0 instance 000001c0589e6ac8 _viewData 00007ffc6c052648 4000003 50 ...ler, DotnetDump]] 0 instance 000001c2189959c0 _logger 00007ffc6c05a3e8 4000004 58 ...Private.CoreLib]] 0 instance 000001c0589e6aa8 _byteBag
查看具体的变量信息dumpobj 内存地址。
第二种:分析内存泄漏
由于上面较为明显的看到内存问题,因此将代码改为,这种代码假设是无意中添加到一个变量_byteBag中。
使用命令:
安装上面的步骤收集转储文件后。进入分析
dumpheap -stat
可以使用参数 -max -min
再次获得所有实例列表
dumpheap -mt 00007ffc69712360
使用gcroot获得根
gcroot -all 000001c95d0b1038
> gcroot -all 000001c95d0b1038
没事不要写静态变量存储数据,依赖注入时代,可以使用单例代替。