[英]Debug High CPU Usage
我有一个使用UCMA(统一通信托管API)4.0 SDK的托管应用程序。 我正在尝试调试应用程序占用100%的CPU且系统挂起的问题。 我已经使用SOS扩展来尝试和调试根本原因。 我目前陷入困境。 我设法找到占用CPU时间的线程ID,但它们大多是非托管线程。 我真的需要帮助。
线程15、18、16、17、19、20都是非托管线程,并且具有相同的调用堆栈。 线程9、10、11、12、13、14都是非托管线程,并且具有相同的调用堆栈。 另一个问题是线程21和22似乎正在等待事件,因此为什么将它们视为消耗CPU时间的失控线程?
有人知道ZwRemoveIoCompletionEx在做什么吗? 是像NtWaitForMultipleObjects这样的休眠对象吗?或者这可能会浪费CPU时间吗? 对于此应用程序,一旦达到100%峰值,它就不会重新启动该应用程序。
0:000> !loadby sos clr
0:009> .time
Debug session time: Wed May 27 15:47:52.000 2015 (UTC - 4:00)
System Uptime: 31 days 1:05:59.329
Process Uptime: 31 days 1:01:27.000
Kernel time: 0 days 21:44:58.000
User time: 1 days 16:51:40.000
0:000> !runaway
User Mode Time
Thread Time
15:113c 0 days 3:46:30.510
18:1418 0 days 3:18:07.135
16:1404 0 days 3:08:01.009
17:140c 0 days 3:07:19.310
19:1428 0 days 3:04:56.943
20:1434 0 days 2:52:51.664
22:1450 0 days 0:47:50.153
9:11dc 0 days 0:45:02.904
21:1440 0 days 0:43:34.623
12:13cc 0 days 0:33:35.298
11:1250 0 days 0:32:50.386
14:fbc 0 days 0:31:57.018
10:1178 0 days 0:29:12.920
13:13c4 0 days 0:28:42.048
2:fa8 0 days 0:03:11.678
4:1164 0 days 0:02:45.080
0:015> kb
RetAddr : Args to Child : Call Site
000007fe`fd36546f : 00000000`272946f0 000007fe`e5394b29 00000000`27295b18 00000000`27295b18 : ntdll!ZwRemoveIoCompletionEx+0xa
00000000`7700c089 : 00000000`1c4981e0 00000000`00000001 00000000`00000001 00000000`00000000 : KERNELBASE!GetQueuedCompletionStatusEx+0xdf
000007fe`e51b634b : 00000000`000009b0 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!GetQueuedCompletionStatusExStub+0x19
000007fe`e538fc0b : 00000000`1c4981e0 00000000`1c4981e0 000007fe`e5905340 00000000`00000000 : rtmpal!RtcPalTaskQueueDequeue+0x17
000007fe`e538f960 : 00000000`1f55fcf0 00000000`00000000 00000000`1db59eb0 00000000`1f55fcf0 : Microsoft_Rtc_Internal_Media!CStreamingEngineImpl::EngineWorkerThread+0x267
000007fe`e51b33c8 : 00000000`00000000 00000000`1c40a6a0 00000000`1c4a4f80 00000000`00000000 : Microsoft_Rtc_Internal_Media!CStreamingEngineImpl::EngineWorkerThreadProc+0xf0
000007fe`f22a3d67 : 00000000`00000000 00000000`1c40a6a0 00000000`00000000 00000000`00000000 : rtmpal!RtcPalSetSchedulerPolicy+0x194
000007fe`f22a3f0e : 000007fe`f233cdb0 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!beginthreadex+0x107
00000000`76fd652d : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!endthreadex+0x192
00000000`7720c541 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d
0:022> !clrstack
OS Thread Id: 0x1450 (22)
Child SP IP Call Site
000000001fdcda68 000000007723186a [HelperMethodFrame_1OBJ: 000000001fdcda68] System.Threading.WaitHandle.WaitMultiple(System.Threading.WaitHandle[], Int32, Boolean, Boolean)
000000001fdcdba0 000007fee968c64c System.Threading.WaitHandle.WaitAny(System.Threading.WaitHandle[], Int32, Boolean)
000000001fdcdc00 000007fe8e097a70 Microsoft.Rtc.Internal.Media.RtpEventHandlerThread.EventHandlerThreadProc()
000000001fdce8d0 000007fee973d0b5 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000001fdcea30 000007fee973ce19 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000001fdcea60 000007fee973cdd7 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
000000001fdceab0 000007fee96b0301 System.Threading.ThreadHelper.ThreadStart()
000000001fdcedc8 000007feed44ffe3 [GCFrame: 000000001fdcedc8]
000000001fdcf0f8 000007feed44ffe3 [DebuggerU2MCatchHandlerFrame: 000000001fdcf0f8]
0:021> kb
RetAddr : Args to Child : Call Site
000007fe`fd331430 : 00000000`00190398 00000000`771f3a92 00000000`c0000008 00000000`00000110 : ntdll!NtWaitForMultipleObjects+0xa
00000000`76fd1220 : 00000000`1edefc18 00000000`1edefc00 00000000`00000000 00000000`00da7a64 : KERNELBASE!WaitForMultipleObjectsEx+0xe8
000007fe`e53bc322 : 00000000`0000cae8 00816179`f67cb320 00000000`1c497eb0 00000000`1edefce0 : kernel32!WaitForMultipleObjects+0xb0
000007fe`e51b33c8 : 00000000`00000000 00000000`00000000 00000000`1dad4630 00000000`1c4a5160 : Microsoft_Rtc_Internal_Media!CStreamingEngineImpl::TimerThreadProc+0x37e
000007fe`f22a3d67 : 00000000`00000000 00000000`1dad4630 00000000`00000000 00000000`00000000 : rtmpal!RtcPalSetSchedulerPolicy+0x194
000007fe`f22a3f0e : 000007fe`f233cdb0 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!beginthreadex+0x107
00000000`76fd652d : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!endthreadex+0x192
00000000`7720c541 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d
0:013> kb
RetAddr : Args to Child : Call Site
000007fe`fd36546f : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwRemoveIoCompletionEx+0xa
00000000`7700c089 : 00000000`00000000 00000000`000000b7 00000000`00000001 00000000`1c4a4a40 : KERNELBASE!GetQueuedCompletionStatusEx+0xdf
000007fe`e51c0fef : 000007fe`e5905340 000007fe`e53eb764 00000000`00000000 00000000`1dac2ab0 : kernel32!GetQueuedCompletionStatusExStub+0x19
000007fe`e53eaf4b : 000007fe`e5905340 00000000`35bdd608 00000000`00000001 00000000`1f17fc20 : rtmpal!RtcPalIOCP::GetQueuedCompletionStatus+0x18f
000007fe`e53eac6d : 00000000`00000510 00000000`0000dddd 00000000`1dad9fe0 00000000`1f17fc80 : Microsoft_Rtc_Internal_Media!CTransportManagerImpl::TransportWorkerThread+0xe7
000007fe`e51b33c8 : 00000000`00000000 00000000`1c409460 00000000`1c4a4e40 00000000`00000000 : Microsoft_Rtc_Internal_Media!CTransportManagerImpl::TransportWorkerThreadProc+0x13d
000007fe`f22a3d67 : 00000000`00000000 00000000`1c409460 00000000`00000000 00000000`00000000 : rtmpal!RtcPalSetSchedulerPolicy+0x194
000007fe`f22a3f0e : 000007fe`f233cdb0 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!beginthreadex+0x107
00000000`76fd652d : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!endthreadex+0x192
00000000`7720c541 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d
使用WinDbg调试性能问题将需要进行几次转储。 一个转储只是时间上的快照,不能为您提供完整的图片。
现在(在进行转储时),线程可能什么都不做。 您确定转储时使用了100%CPU吗? 还是在进行转储前一毫秒内从100%恢复?
!runaway
显示的值是程序整个生命周期内的累积值。 这只是告诉您该线程在过去已经工作了很多。 它不会告诉您现在正在做什么或将来将要做什么。
尽管它是由马克·鲁西诺维奇(Mark Russinovich)和其他一些专家完成的,但对于初学者而言,这并不是一件容易的事。
由于您需要很多转储才能获得完整的图片,因此请使用其他工具来分析性能问题。 典型的工具称为探查器,例如Redgate的ANTS探查器或JetBrains的dotTrace。
如果您确实想采用这种方法,请至少将ProcDump(SysInternals)与-ma -c -n -s
选项一起使用以收集一些不错的CPU高转储。
尝试从进程资源管理器和将procmon Sysinternals的 。 尽管它可能无法立即为您提供答案,但它为流程提供了许多上下文,并可能有助于您了解应用程序正在执行的不同操作。 在ProcMon中,只需将过滤器设置为您感兴趣的任何ProcessName。 在进程资源管理器中,找到进程,右键单击->属性。 您将看到诸如线程和TCP连接之类的内容以及许多其他内容。
一切都很好。 这里有一个问题,你用windbg
得到一个堆栈跟踪,有一些建议,然后个唱当你说出了神奇的话“生产环境”世界变了。
关于您的其余帖子,我注意到了这一点:
对于此应用程序,一旦达到100%峰值,它就不会重新启动该应用程序。
基本上,这意味着它已损坏,并且已严重损坏。
我还观察到您有一个多线程应用程序,这使得找出问题出处变得更加困难。
在生产环境中不应该做的事情
好吧,基本上列表是:
如果您有一个100%的CPU峰值永不下降,那么查看其余的软件开发过程也可能很有趣。 您有自动(功能性)测试代码吗? 您是否使用代码覆盖率来检查要测试的内容? 简而言之:您认为自己的环境稳定吗?
目前,这对您没有任何帮助。 也就是说,修复错误后,我认为长期考虑这些问题很重要。 我不确定这是否适用于您的情况-但根据我的经验,您通常会遇到类似这样的错误,这意味着您仍有很多工作要做。
它已经坏了,所以不可能破解
首先,让我们对其进行修复。 让我们面对残酷的事实。 它已经被破坏了,所以如果我们暂时将其破坏,那就很好了。
问题是100%CPU。 您需要知道的是CPU使用率在代码中的位置。 探查器是最适合的工具。
获得像Red Gate ANTS这样的专业性能分析器。 安装,开始。 另外,您需要在生产服务器上放置PDB和源代码(与开发计算机相同的文件夹结构),并且我可能会在其中放置调试DLL。 这只是暂时的,在我们发现错误之后,这些东西应该会再次消失。 正如我所说,您不希望在生产环境中使用此功能。
不要对您的生产应用程序保持温和,仅对源代码使用“行级”或“方法级”配置文件。 它不会破坏您的应用程序,只会使其变慢。 您也可以“暂停”探查器,这基本上意味着不再收集任何采样数据-在错误到达之前,这是一个好主意。
当错误出现时,再次继续分析器,并捕获一些数据。
调试器
以我的经验,对应用程序进行调试和“堆栈跟踪”有时会破坏它们。 我不确定何时会发生这种情况-但在所说的生产环境中,您应该在停止调试过程后重新启动要调试的应用程序。
sysinternals的process explorer
器是一种可能的堆栈跟踪应用程序。 以管理员身份运行,双击进程,转到“线程”选项卡,然后为每个线程单击“堆栈跟踪”(或双击),直到发现有趣的东西。
如果您发现了Wait
或Sleep
,那可能就好了。
祝好运!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.