次の方法で共有


プロセッサ消費の追跡

1 つのアプリケーションがプロセッサのすべてのアテンションを消費している ("占有している") 場合、他のプロセスは "リソース不足" になり、実行できなくなります。

この種のバグを修正するには、以下の手順を使用します。

すべての CPU サイクルを使用しているアプリケーションのデバッグ

  1. この問題の原因となっているアプリケーションを特定する:タスク マネージャーまたは Perfmon を使用して、プロセッサ サイクルの 99% または 100% を使用しているプロセスを見つけます。 これにより、問題のあるスレッドもわかることがあります。

  2. このプロセスに WinDbg、KD、または CDB をアタッチします。

  3. 問題の原因となっているスレッドを特定する: 問題のあるアプリケーションに割り込みます。 !runaway 3 拡張機能を使用して、すべての CPU 時間が消費されている場所の "スナップショット" を作成します。 g (実行) を使用し、数秒待ちます。 その後、割り込みを行い、もう一度 !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
    

    2 つの数値セットを比較し、ユーザー モード時間またはカーネル モード時間が最も増加しているスレッドを探します。 !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 と表示されています。 戻りアドレスは、2 行目に表示されている関数オフセット (BuggyProgram!OpenDestFileStream+0xB3) と等価です。 アプリケーションで使用できるシンボルがない場合、関数名が表示されないことがあります。 g (実行) コマンドを使用し、シンボリック アドレスまたは 16 進数アドレスを使用して、この戻りアドレスに到達するまで実行します。

    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. もう一度スレッドに割り込み、bp (ブレークポイントの設定) コマンドを使用して BuggyProgram!SaveMsgToDestFolder+0xB3 にブレークポイントを設定します。 その後、g コマンドを繰り返し使用します。 ターゲットを何回実行しても、このブレークポイントにすぐにヒットする場合、問題のある関数が特定された可能性が非常に高くなります。

    0:002> bp BuggyProgram!SaveMsgToDestFolder+0xb3
    
    0:002> g 
    
    0:002> g 
    
  10. p (ステップ実行) コマンドを使用して、命令のループ シーケンスが存在する場所を特定するまで関数を続行します。 その後、アプリケーションのソース コードを分析して、スピンしているスレッドの原因を特定できます。 通常、原因は、whiledo-whilegoto、または for ループのロジックの問題であることが判明します。