1. 程式人生 > >Windbg程式除錯系列5-高CPU問題分析

Windbg程式除錯系列5-高CPU問題分析

上篇部落格中給大家分享了使用Windbg進行Live Debugging:

本篇中我們繼續,跟大家分享常見的應用程式高CPU使用率問題分析。

先說Windows下CPU使用率這個概念:

CPU使用率:在工作管理員的重新整理週期內CPU忙的時間與整個重新整理週期的比值。預設的重新整理週期是1s。

即1s內,反映出系統的CPU繁忙程度

我們開啟Windows的工作管理員,可以看到CPU的使用率:

當然,這個CPU使用率是整個所有核心CPU的使用率。比如我本機是8核心的CPU。整體的CPU使用率 在某一瞬間是14%。

這個CPU使用率是如何計算出來的,有兩個重要的時間sysTime和idleTime:

sysTime:表示該時間段內總的CPU時間=CPU處於使用者態和核心態CPU時間的總和,即sysTime =kerneTimel + userTime

(注:這裡並不包括idleTime,因為當CPU處於空閒狀態時,是在核心模式下執行System Idle Process這個程序,所以kernelTime實際上已經包含了idleTime);

idleTime:表示在該時間段內CPU處於空閒狀態的時間;

CPU% = 1 – idleTime / sysTime * 100

 說到這裡,我們分析一個應用的高cpu問題,更多的是:分析使用者態的CPU耗時。即,我們應用程式本身執行時消耗的CPU時間片總和。

然後,進入今天的正題,使用Windbg分析高CPU問題:

一、首先我們用C#寫一個Any CPU架構的Console模擬程式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace HighCpuDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var normalThread 
= new Thread(NormalMethod);             normalThread.Start();             var longRunningThread = new Thread(LongRunningMethod);             longRunningThread.Start();             Console.ReadKey();         }         private static void NormalMethod()         {             int a = 0;             int b = 100000;             var list = new List<int>();             for (int i = 0; i < b; i++)             {                 a += i;                 list.Add(a);                 var max = list.Max();                 var min = list.Min();                 var avg = list.Average();                 Console.WriteLine(string.Format("Thread:{0}, writeline:{1}", Thread.CurrentThread.ManagedThreadId, a));                 //休息一下                 Thread.Sleep(100);             }         }         private static void LongRunningMethod()         {             for (int c = 0; c < 100000; c++)             {                 int a = 0;                 int b = 100000;                 var list = new List<int>();                 for (int i = 0; i < b; i++)                 {                     a += i;                     list.Add(a);                     var max = list.Max();                     var min = list.Min();                     var avg = list.Average();                     Console.WriteLine(string.Format("Thread:{0}, writeline:{1}", Thread.CurrentThread.ManagedThreadId, a));                 }             }         }     } }

程式碼中有兩個執行緒,一個是“正常”的計算輸出執行緒NormalThread(每次輸出,會休息一下 100s),一個是長時間執行的執行緒LongRunningThread,一直在計算,輸出。

程式碼寫好之後,設定為Any CPU架構,支援64位模式:

看程式輸出:

很明顯,3號執行緒是NormalThread, 4號執行緒是LongRunningThread。

二、 檢視應用程序的CPU使用率

從工作管理員上,能夠發現,HighCpuDemo這個程序的CPU使用率是12%

三、間隔30s,抓兩個Dump

這裡有個問題:為什麼要間隔一段時間抓2個dump?我們先把問題放在這。

四、使用Windbg分析兩個Dump檔案,使用!runaway找到最消耗CPU時間片的執行緒,然後優化

Windbg開啟這兩個Dump後,分別執行以下命令:

0:000> .loadby sos clr
0:000> !runaway

對比看著兩個Dump的輸出:

第一個Dump:

Debug session time: Sun Nov 25 20:16:39.000 2018 (GMT+8)
System Uptime: 0 days 3:03:00.195
Process Uptime: 0 days 0:08:31.000
.............................
Loading unloaded module list
.
ntdll!ZwDeviceIoControlFile+0x14:
00007ffc`c01b03a4 c3              ret
0:000> .loadby sos clr
0:000> !runaway
 User Mode Time
  Thread       Time
   4:3758      0 days 0:07:38.531
   3:325c      0 days 0:00:00.390
   0:2248      0 days 0:00:00.015
   6:4c3c      0 days 0:00:00.000
   5:17d0      0 days 0:00:00.000
   2:278       0 days 0:00:00.000
   1:2424      0 days 0:00:00.000

第二個Dump:

Debug session time: Sun Nov 25 20:17:06.000 2018 (GMT+8)
System Uptime: 0 days 3:03:27.136
Process Uptime: 0 days 0:08:58.000
.............................
Loading unloaded module list
.
ntdll!ZwDeviceIoControlFile+0x14:
00007ffc`c01b03a4 c3              ret
0:000> .loadby sos clr
0:000> !runaway
 User Mode Time
  Thread       Time
   4:3758      0 days 0:08:01.984
   3:325c      0 days 0:00:00.406
   0:2248      0 days 0:00:00.015
   6:4c3c      0 days 0:00:00.000
   5:17d0      0 days 0:00:00.000
   2:278       0 days 0:00:00.000
   1:2424      0 days 0:00:00.000

這裡有個關鍵的Windbg指令  !runaway, 它有什麼作用,輸出的是什麼:

This extension is a quick way to find out which threads are spinning out of control or consuming too much CPU time.

The display identifies each thread by the debugger's internal thread numbering and by the thread ID in hexadecimal. The debugger IDs are also shown.

Here is an example: 


0:001> !runaway 7

 User Mode Time
 Thread       Time
 0:55c        0:00:00.0093
 1:1a4        0:00:00.0000

 Kernel Mode Time
 Thread       Time
 0:55c        0:00:00.0140
 1:1a4        0:00:00.0000

 Elapsed Time
 Thread       Time
 0:55c        0:00:43.0533
 1:1a4        0:00:25.0876

使用這個指令,可以檢視每個執行緒的"使用者態"CPU使用時間:

從上面兩個Dump中,我們能看出,4號執行緒 User Mode Time 一直在增加,我們看看4號執行緒的堆疊:

0:000> ~4s
*** WARNING: Unable to verify checksum for System.Core.ni.dll
System_Core_ni+0x588b44:
00007ffc`a4268b44 488b4de8        mov     rcx,qword ptr [rbp-18h] ss:000000c1`df0ff2a8=000001d4633eb280
0:004> !clrstack
OS Thread Id: 0x3758 (4)
        Child SP               IP Call Site
000000c1df0ff280 00007ffca4268b44 System.Linq.Enumerable.Min(System.Collections.Generic.IEnumerable`1<Int32>)
000000c1df0ff2d0 00007ffc4b930660 *** WARNING: Unable to verify checksum for HighCpuDemo.exe
HighCpuDemo.Program.LongRunningMethod() [c:\users\zhougq\documents\visual studio 2015\Projects\HighCpuDemo\Program.cs @ 54]
000000c1df0ff3a0 00007ffca7e24770 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 954]
000000c1df0ff470 00007ffca7e24604 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 902]
000000c1df0ff4a0 00007ffca7e245d2 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 891]
000000c1df0ff4f0 00007ffca7eacff2 System.Threading.ThreadHelper.ThreadStart() [f:\dd\ndp\clr\src\BCL\system\threading\thread.cs @ 111]
000000c1df0ff748 00007ffcaaf35863 [GCFrame: 000000c1df0ff748] 
000000c1df0ffa98 00007ffcaaf35863 [DebuggerU2MCatchHandlerFrame: 000000c1df0ffa98] 

正如我們程式碼中所寫的,LongRunningMethod方法一直在執行、消耗CPU資源。

定位到程式碼問題,就可以進一步修改程式碼,解決問題了。

以上就是使用Windbg 除錯高CPU問題的方法思路,總結一下:

1. 檢視應用程序的CPU使用率
2. 間隔一段時間,抓兩個Dump
3. 使用Windbg分析兩個Dump檔案,使用!runaway找到最消耗CPU時間片的執行緒,然後優化

 分享給大家。

周國慶

2018/11/25

相關推薦

Windbg程式除錯系列5-CPU問題分析

上篇部落格中給大家分享了使用Windbg進行Live Debugging: 本篇中我們繼續,跟大家分享常見的應用程式高CPU使用率問題分析。 先說Windows下CPU使用率這個概念: CPU使用率:在工作管理員的重新整理週期內CPU忙的時間與整個重新整理週期的比值。預設的重新整理週期是1s。 即

Windbg程式除錯系列3-執行緒阻塞問題

上一篇博文給大家分享了使用Windbg分析記憶體洩露問題: Windbg程式除錯系列2-記憶體洩露問題 本篇我們繼續跟大家分享,如何分析解決執行緒阻塞問題。 從根本上講,執行緒阻塞屬於程式Hang的一種,其表現主要有: 1. 隨著請求的增加,執行緒數一直增加,可能會把執行緒池打爆

Windbg程式除錯系列4-Live Debugging

上篇博文中給大家分享了使用Windbg分析執行緒阻塞問題: Windbg程式除錯系列3-執行緒阻塞問題 本篇中我們繼續,跟大家分享附加程序實時除錯-Live Debugging。 先說一下使用Windbg附加程序實時除錯的應用場景和注意事項: 應用場景: 整合測試環境,影響異常後,分析異常和執

Windbg程式除錯系列1-常用命令說明&示例

Windbg程式除錯是.Net高階開發需要掌握的必備技能,分析記憶體洩露、分析高CPU、分析執行緒阻塞、分析記憶體物件、分析執行緒堆疊、Live Dedugging。這個領域可以說一個技能+場景化應用的結合,如果單學Windbg命令,不理解實際Troubleshooting中的作用,是沒有意義的。所以,準備搞

Windbg程式除錯系列2-記憶體洩露問題

上篇文章給大家解釋了Windbg的基本命令和說明,這一篇給大家介紹記憶體洩露場景的問題分析。 文章大綱: 描述問題背景和現象 確定問題是否是記憶體洩露 梳理問題分析思路 動手分析解決 總結 1. 先說問題背景:生產環境IIS站點,執行一段時間後,w3wp程序記憶體會漲到2G,同時記憶體不

Windbg程式除錯系列1-常用命令說明&Mex擴充套件使用總結

Windbg程式除錯是.Net高階開發需要掌握的必備技能,分析記憶體洩露、分析高CPU、分析執行緒阻塞、分析記憶體物件、分析執行緒堆疊、Live Dedugging。這個領域可以說一個技能+場景化應用的結合,如果單學Windbg命令,不理解實際Troubleshooting中

微信小程式開發系列——5.前端頁面開發

摘要:本文說明了微信前端頁面開發的基本架構,說明了組成檔案各自的詳細結構,通過這幾個檔案的協同工作,微信小程式開發框架可以實現頁面Page中檢視層和邏輯層的統一。 0. 簡介 根據之前開發者工具和開發框架簡介的內容,我們把官方demo和開發者工具安裝好以

Linux系統內對CPU的監控及日誌分析

文件 mos anti sage them 其中 generate ted cpu 使用linux系統時,占用cpu資源過高和,用腳本排查: 1,實時監控,一旦有cpu占用高的進程,程序啟動; 2,再對進程分析,得出對應線程; 3,對對應線程所在的程序日誌文檔進行分析,比如

壓測過程中故障排查之一:CPU占用問題分析案例

一段 運行 應用 進行 返回 sco close 找到 java 說明: 一個應用占用CPU很高,除了確實是計算密集型應用之外,通常原因都是出現了死循環 以我們最近出現的一個實際故障為例,介紹怎麽定位和解決這類問題。 根據top命令,發現PID為28555的Java進程占

程式異常崩潰後用windbg輔助除錯解決的經驗

狀況:我的程式呼叫別人的庫做 檔案寫入工作。           在這一過程中出現異常,程式崩潰。           經反覆檢查,認為自己的程式沒有錯,但無法判斷在別人庫裡哪裡有錯。   &

java應用佔用cpu原因分析

線上伺服器cpu佔用過高問題排查 1、定位最耗cpu的程序 命令:top 2、定位最耗cpu的執行緒 命令:Top –Hp PID 例如:Top –Hp 12086 3、列印執行緒堆疊資訊 命令:Printf ‘%x\n’ PID 例如:printf

微信小程式之登入頁例項 —— 微信小程式實戰系列5

提供一個登入頁的案例,供同學們使用 專案效果圖: 目錄結構: 圖片資源: name.png key.png loginLog.jpg login.wxml: <view c

Expert 診斷優化系列------------------你的CPU麼?

    現在很多使用者被資料庫的慢的問題所困擾,又苦於花錢請一個專業的DBA成本太高。軟體維護人員對資料庫的瞭解又不是那麼深入,所以導致問題遲遲不能解決,或只能暫時解決不能得到根治。開發人員解決資料問題基本又是搜遍百度各種方法嘗試個遍,可能錯過診斷問題的最佳時機又可能嘗試一堆方法最後無奈放棄。     怎麼

通過 thread dump 分析找到CPU耗用與記憶體溢位的Java程式碼

但實際上,我們是可以幫助他們的,效果好的話還可以定位到具體出問題的程式碼行數,思路如下: 1.通過對CPU與記憶體的耗用情況判斷是否存在問題; 2.通過top命令找到可疑的執行緒的ID; 3.確認應用伺服器的console資訊的輸出位置; 4.通過kill -3 ID 的方式獲取thread dump資訊;

hadoop叢集System Cpu消耗過問題分析--記憶體碎片整合問題

Hadoop叢集伺服器升級為rhel6核心後,System Cpu佔用非常高,有任務執行的時候經常到50%以上。對其中一臺機器一天的執行狀態取樣的資料: idle: 76%   sys:14%  user: 9% 從取樣資料中,可以發現System Cpu比User Cpu

cpu load過問題分析和解決

基本思維是有東西佔用的CPU_QUEUE,檢視一下程序的狀態。 top -H shift+o =選擇w (按照狀態排序) **1. 首先排查哪些程序cpu佔用率高。 通過命令 ps ux 2. 檢視對應Java程序的每個執行緒的CPU佔用率。通

linux驅動由淺入深系列通sensor架構例項分析之一

本系列導航: 最初的時候晶片廠家對sensor的處理和對待其它外設一樣都是直接掛在processor上,sensor的驅動也和其他linux或android的驅動一樣,生成對應的裝置節點給上層提供資料(關於此類linux基礎驅動的知識,可以參考本部落格其他博文)

Android學習筆記整理(5)--Android程式除錯

每個Android應用上線之前都會進行一系列的測試,確保應用能夠正常使用。通常使用JUnit單元測試,另外還可以使用LogCat(日誌控制檯)來除錯錯誤。一、JUnit單元測試1.配置JUnit環境在進行JUnit測試時,我們需要在AndroidManifest.xml的&l

TPC-H系列---5---TPC-H的22條查詢語句分析(Q6--Q8)

  Q6,預測收入變化查詢Q6語句查詢得到某一年中通過變換折扣帶來的增量收入。這是典型的“what-if”判斷,用來尋找增加收入的途徑。預測收入變化查詢考慮了指定的一年中折扣在“DISCOUNT-0.01”和“DISCOUNT+0.01”之間的已運送的所有訂單,求解把l_quantity小於quantity的

windbg+vmware除錯驅動 x86 x64 (適合主機為xp且vmware為6.5的環境)

       除錯驅動使用此文方法已過時,可以參考使用visualddk+vmware+windbg,具體請參考以下連結:(添加於2014-1-2)     近來一直在學習驅動相關內容,所以自然牽涉到除錯驅動的問題。查閱資料甚多,但還未發現有能把整個除錯框架串起來的資料