追蹤處理器 Hog

如果某個應用程式耗用 (「擷取」) 所有處理器的注意力,其他進程最終會「耗盡」且無法執行。

使用下列程式修正此排序的 Bug。

偵錯使用所有 CPU 週期的應用程式

  1. 識別造成此問題的應用程式: 使用 工作管理員Perfmon 來尋找處理器週期的 99% 或 100% 進程。 這可能也會告訴您有問題的執行緒。

  2. 將 WinDbg、KD 或 CDB 附加至此程式。

  3. 識別造成問題的執行緒: 中斷至違規的應用程式。 使用 !runaway 3 延伸模組來擷取所有 CPU 時間的「快照集」。 使用 g (Go) 並等候幾秒鐘。 然後中斷並再次使用 !runaway 3

    0:002> !runaway 3
     User Mode Time
     Thread    Time
     4e0        0:12:16.0312
     268        0:00:00.0000
     22c        0:00:00.0000
     Kernel Mode Time
     Thread    Time
     4e0        0:00:05.0312
     268        0:00:00.0000
     22c        0:00:00.0000
    
    0:002> g
    
    0:001> !runaway 3
     User Mode Time
     Thread    Time
     4e0        0:12:37.0609
     3d4        0:00:00.0000
     22c        0:00:00.0000
     Kernel Mode Time
     Thread    Time
     4e0        0:00:07.0421
     3d4        0:00:00.0000
     22c        0:00:00.0000
    

    比較兩組數位,並尋找使用者模式時間或核心模式時間已增加最多之執行緒。 因為 !runaway 會依遞減 CPU 時間排序,所以違規執行緒通常是清單頂端的執行緒。 在此情況下,執行緒0x4E0會造成問題。

  4. 使用 ~ (執行緒狀態) 和 ~s (設定目前線程) 命令,將此設為目前的執行緒:

    0:001> ~
       0  Id: 3f4.3d4 Suspend: 1 Teb: 7ffde000 Unfrozen
    .  1  Id: 3f4.22c Suspend: 1 Teb: 7ffdd000 Unfrozen
     2  Id: 3f4.4e0 Suspend: 1 Teb: 7ffdc000 Unfrozen
    
    0:001> ~2s
    
  5. 使用 kb (顯示堆疊回溯) 來取得此執行緒的堆疊追蹤:

    0:002> kb
    FramePtr  RetAddr   Param1   Param2   Param3   Function Name
    0b4ffc74  77f6c600  000000c8.00000000 77fa5ad0 BuggyProgram!CreateMsgFile+0x1b
    0b4ffce4  01836060  0184f440 00000001 0b4ffe20 BuggyProgram!OpenDestFileStream+0xb3
    0b4ffd20  01843eba  02b5b920 00000102 02b1e0e0 BuggyProgram!SaveMsgToDestFolder+0xb3
    0b4ffe20  01855924  0b4ffef0 00145970 0b4ffef0 BuggyProgram!DispatchToConn+0xa4
    0b4ffe5c  77e112e6  01843e16 0b4ffef0 0b4fff34 RPCRT4!DispatchToStubInC+0x34
    0b4ffeb0  77e11215  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStubWorker@RPC_INTERFACE@@AAEJPAU_RPC_MESSAGE@@IPAJ@Z+0xb0
    0b4ffed0  77e1a3b1  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStub@RPC_INTERFACE@@QAEJPAU_RPC_MESSAGE@Z+0x41
    0b4fff40  77e181e4  02b1e0b0 00000074 0b4fff90 RPCRT4!?ReceiveOriginalCall@OSF_SCONNECTION@Z+0x14b
    0b4fff60  77e1a5df  02b1e0b0 00000074 00149210 RPCRT4!?DispatchPacket@OSF_SCONNECTION@+0x91
    0b4fff90  77e1ac1c  77e15eaf 00149210 0b4fffec RPCRT4!?ReceiveLotsaCalls@OSF_ADDRESS@@QAEXXZ+0x76
    
  6. 在目前執行之函式的傳回位址上設定中斷點。 在此情況下,傳回位址會顯示在第一行上,如0x77F6C600所示。 傳回位址相當於第二行顯示的函式位移, (BuggyProgram!OpenDestFileStream+0xB3) 。 如果應用程式沒有可用的符號,則可能不會顯示函式名稱。 使用 g (Go) 命令來執行,直到達到此傳回位址為止,請使用符號或十六進位位址:

    0:002> g BuggyProgram!OpenDestFileStream+0xb3
    
  7. 如果叫用此中斷點,請重複此程式。 例如,假設叫用此中斷點。 應採取下列步驟:

    0:002> kb
    FramePtr  RetAddr   Param1   Param2   Param3   Function Name
    0b4ffce4  01836060  0184f440 00000001 0b4ffe20 BuggyProgram!OpenDestFileStream+0xb3
    0b4ffd20  01843eba  02b5b920 00000102 02b1e0e0 BuggyProgram!SaveMsgToDestFolder+0xb3
    0b4ffe20  01855924  0b4ffef0 00145970 0b4ffef0 BuggyProgram!DispatchToConn+0xa4
    0b4ffe5c  77e112e6  01843e16 0b4ffef0 0b4fff34 RPCRT4!DispatchToStubInC+0x34
    0b4ffeb0  77e11215  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStubWorker@RPC_INTERFACE@@AAEJPAU_RPC_MESSAGE@@IPAJ@Z+0xb0
    0b4ffed0  77e1a3b1  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStub@RPC_INTERFACE@@QAEJPAU_RPC_MESSAGE@Z+0x41
    0b4fff40  77e181e4  02b1e0b0 00000074 0b4fff90 RPCRT4!?ReceiveOriginalCall@OSF_SCONNECTION@Z+0x14b
    0b4fff60  77e1a5df  02b1e0b0 00000074 00149210 RPCRT4!?DispatchPacket@OSF_SCONNECTION@+0x91
    0b4fff90  77e1ac1c  77e15eaf 00149210 0b4fffec RPCRT4!?ReceiveLotsaCalls@OSF_ADDRESS@@QAEXXZ+0x76
    
    0:002> g BuggyProgram!SaveMsgToDestFolder+0xb3
    

    如果達到此動作,請繼續進行:

    0:002> kb
    FramePtr  RetAddr   Param1   Param2   Param3   Function Name
    0b4ffd20  01843eba  02b5b920 00000102 02b1e0e0 BuggyProgram!SaveMsgToDestFolder+0xb3
    0b4ffe20  01855924  0b4ffef0 00145970 0b4ffef0 BuggyProgram!DispatchToConn+0xa4
    0b4ffe5c  77e112e6  01843e16 0b4ffef0 0b4fff34 RPCRT4!DispatchToStubInC+0x34
    0b4ffeb0  77e11215  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStubWorker@RPC_INTERFACE@@AAEJPAU_RPC_MESSAGE@@IPAJ@Z+0xb0
    0b4ffed0  77e1a3b1  0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStub@RPC_INTERFACE@@QAEJPAU_RPC_MESSAGE@Z+0x41
    0b4fff40  77e181e4  02b1e0b0 00000074 0b4fff90 RPCRT4!?ReceiveOriginalCall@OSF_SCONNECTION@Z+0x14b
    0b4fff60  77e1a5df  02b1e0b0 00000074 00149210 RPCRT4!?DispatchPacket@OSF_SCONNECTION@+0x91
    0b4fff90  77e1ac1c  77e15eaf 00149210 0b4fffec RPCRT4!?ReceiveLotsaCalls@OSF_ADDRESS@@QAEXXZ+0x76
    
    0:002> g BuggyProgram!DispatchToConn+0xa4
    
  8. 最後,您會發現未叫用的中斷點。 在此情況下,您應該假設最後一個 g 命令會設定執行中的目標,但未中斷。 這表示 SaveMsgToDestFolder () 函式永遠不會傳回。

  9. 再次中斷線程,並在BuggyProgram 上設定中斷點!SaveMsgToDestFolder+0xB3搭配 bp (Set Breakpoint) 命令。 然後重複使用 g 命令。 如果此中斷點立即叫用,不論您執行目標多少次,您很可能已識別出違規函式:

    0:002> bp BuggyProgram!SaveMsgToDestFolder+0xb3
    
    0:002> g 
    
    0:002> g 
    
  10. 使用 p (步驟) 命令繼續進行 函式,直到您識別指令迴圈序列的位置為止。 然後,您可以分析應用程式的原始程式碼,以識別旋轉執行緒的原因。 原因通常會在 whiledo-whilegotofor 迴圈的邏輯中產生問題。