Identyfikacja pożeracza zasobów procesora

Jeśli jedna aplikacja zawłaszcza całą uwagę procesora, inne procesy będą 'głodować' i nie będą w stanie działać.

Użyj poniższej procedury, aby poprawić usterkę tego rodzaju.

Debugowanie aplikacji korzystającej ze wszystkich cykli procesora CPU

  1. Zidentyfikuj, która aplikacja powoduje ten problem: Użyj Menedżera zadań lub narzędzia Perfmon , aby znaleźć, który proces używa 99% lub 100% cykli procesora. Może to również wskazać problematyczny wątek.

  2. Dołącz windbg, KD lub CDB do tego procesu.

  3. Zidentyfikuj, który wątek powoduje problem: Włamaj się do aplikacji naruszającej dane. Użyj rozszerzenia !runaway 3, aby zrobić "migawkę" pokazującą, gdzie zużywany jest cały czas procesora. Użyj g (Go) i zaczekaj kilka sekund. Następnie przerwij i użyj !runaway 3 ponownie.

    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
    

    Porównaj dwa zestawy liczb i poszukaj wątku, którego czas trybu użytkownika lub czas trybu jądra wzrósł najbardziej. Ponieważ !runaway sortuje według malejącego czasu procesora CPU, wątek powodujący problem jest zwykle tym na szczycie listy. W tym przypadku wątek 0x4E0 powoduje problem.

  4. Użyj poleceń ~ (stan wątku) i ~s (Ustaw bieżący wątek), aby wykonać ten bieżący wątek:

    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. Użyj kb (Display Stack Backtrace), aby uzyskać ślad stosu tego wątku:

    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. Ustaw punkt przerwania na adres zwrotny aktualnie uruchomionej funkcji. W takim przypadku adres zwrotny jest wyświetlany w pierwszym wierszu jako 0x77F6C600. Adres zwrotny jest równoważny przesunięciu funkcji wyświetlanemu w drugim wierszu (BuggyProgram!OpenDestFileStream+0xB3). Jeśli dla aplikacji nie są dostępne żadne symbole, nazwa funkcji może nie być widoczna. Użyj polecenia g (Go), aby wykonać polecenie do momentu osiągnięcia tego adresu zwrotnego przy użyciu adresu symbolicznego lub szesnastkowego:

    0:002> g BuggyProgram!OpenDestFileStream+0xb3
    
  7. Jeśli ten punkt przerwania zostanie trafiony, powtórz proces. Załóżmy na przykład, że ten punkt przerwania został trafiony. Należy wykonać następujące czynności:

    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
    

    Jeśli zostanie to trafione, kontynuuj wykonywanie następujących czynności:

    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. Na koniec znajdziesz punkt przerwania, który nie zostanie aktywowany. W tym przypadku należy założyć, że ostatnie polecenie g uruchomiło docelowy element i nie zostało przerwane. Oznacza to, że funkcja SaveMsgToDestFolder() nigdy nie zwróci.

  9. Ponownie włamaj się do wątku i ustaw punkt przerwania w BuggyProgram! SaveMsgToDestFolder+0xB3 za pomocą polecenia bp (Ustaw punkt przerwania). Następnie użyj polecenia g wielokrotnie. Jeśli ten punkt przerwania trafi natychmiast, niezależnie od tego, ile razy wykonano cel, jest bardzo prawdopodobne, że zidentyfikowano funkcję powodującą problem:

    0:002> bp BuggyProgram!SaveMsgToDestFolder+0xb3
    
    0:002> g 
    
    0:002> g 
    
  10. Użyj polecenia p (Krok), aby przejść przez funkcję do momentu zidentyfikowania miejsca, w którym znajdują się sekwencja pętli instrukcji. Następnie możesz przeanalizować kod źródłowy aplikacji, aby zidentyfikować przyczynę wirującego wątku. Przyczyna zwykle okaże się problemem w logice while, do-while, goto lub for pętli.