3

私のソフトウェアを使用しているクライアントの 1 つで行き止まりの状況に陥っています。販売された約 40 個の製品 (VB.NET 2005 を使用して .NET 2.0 でプログラムされたアプリケーション) のうち、約 2 個が応答しなくなり、デュアル コア CPU の 1 つのコアが 100% でスタックします (プログラムは 1 つのコアのみを使用します)。

最も論理的な推測は、この動作の原因となる無限ループですが、非常に多くのループを含む数千行のコードです。私が入手した情報は以上です。さて、この問題のデバッグにどのようにアプローチすることをお勧めしますか?

編集: 基本的に、ソフトウェアは、PC などの他のデバイスを使用して消費されたクレジットの量を計算する責任があります。これは Cyber​​cafe 管理プログラムであり、断続的に失敗します。つまり、失敗するとクレジットが差し引かれます。データベースのバックアップを作成する時期かどうかを確認するなど、他のこともバックグラウンドで実行します。

編集:解決しました。それは最もありそうもない問題でした。私が DBMS として使用した Access データベース エンジンは、実際には問題のあるアプリケーションの一部です。テーブルの 1 つで行 - JUST ONE FRIGGIN ROW - を操作するのは困難です。それを削除したり、他のテーブルのその行に関連するレコードを追加したりすることはできません。MS Access 2007 でさえ、その行を操作しようとすると CPU が 100% まで上昇します!

簡単な「圧縮して修復」コマンドですべてが修正されました。アプリケーションが起動するたびにそのコマンドを発行すると思います。そうすることで、これが再び起こるのを防ぐことができます。

WinDbg のおかげで、問題の場所を見つけることができました。リアルタイムセーバーなので、使い方を学ぶことをお勧めします。

4

8 に答える 8

7

ターゲット マシンに windbg (Windows デバッガー) をインストールします。デバッガーを起動し、疑わしいプロセスにアタッチしてプログラムを実行し、問題が発生するまで待ちます。問題が発生したら、デバッガーのコマンド ラインで次のコマンドを呼び出します。

!逃げる

これにより、どのスレッドが最も多くの時間を消費しているかがわかります。次に、ほとんどの CPU リソースを消費しているスレッドから、いくつかのスレッド スタックを取得します。

次に例を示します。

0:015> !runaway

ユーザーモード時間 スレッド時間 0:1074 0 日 0:00:21.637 11:137c 0 日 0:00:02.792 4:12c8 0 日 0:00:00.530 9:1374 0 日 0:00:00.046 15:13d0 0 日0:00:00.000 14:1204 0 日 0:00:00.000 13:154c 0 日 0:00:00.000 12:144c 0 日 0:00:00.000 10:1378 0 日 0:00:00.000 8:1340 0 日0:00:00.000 7:12f0 0 日 0:00:00.000 6:12d4 0 日 0:00:00.000 5:12d0 0 日 0:00:00.000 3:12c4 0 日 0:00:00.000 2:12c0 0 日0:00:00.000 1:12b4 0 日 0:00:00.000

ここで、リストの 2 番目のスレッドであるスレッド 11 のコール スタックが必要であると仮定すると、最初にスレッド 11 に切り替えます。これは、~11s と入力することで実行できます。

0:015> ~11s

EAX = 03FBB270 EBX = FFFFFFFF ECX = 00000002 EDX = 00000060 ESI = 00000000 EDI = 000000 EIP = 77475E74 ESP = 0572F60C EBP = 0572F67C IOPL = 0 NV UP EI PL ZR NA PE NC CS 0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCallRet: 77475e74 c3 ret

kp を実行して、このスレッドのコール スタックを取得します。

0:011> kp
ChildEBP RetAddr  
0572f608 77475620 ntdll!KiFastSystemCallRet
0572f60c 75b09884 ntdll!NtWaitForSingleObject+0xc
0572f67c 75b097f2 kernel32!WaitForSingleObjectEx+0xbe
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Mozilla Firefox 3.1 Beta 1\nspr4.dll - 
0572f690 10019a0b kernel32!WaitForSingleObject+0x12
WARNING: Stack unwind information not available. Following frames may be wrong.
0572f6ac 10015979 nspr4!PR_MD_WAIT_CV+0x8b
0572f6c4 10015763 nspr4!PR_GetPrimordialCPU+0x79
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Mozilla Firefox 3.1 Beta 1\xul.dll - 
0572f6e0 64d44d6a nspr4!PR_Wait+0x33
0572f708 64dbe67e xul!NS_CycleCollectorForget2_P+0x698a
0572f72c 10019b3f xul!gfxWindowsPlatform::FontEnumProc+0xfd4e
0572f734 10015d32 nspr4!PR_MD_UNLOCK+0x1f
0572f738 1001624b nspr4!PR_Unlock+0x22
0572f754 1001838d nspr4!PRP_TryLock+0x4cb
00000000 00000000 nspr4!PR_Now+0x109d

コマンド kp はパラメータを出力します。ローカル変数は dv で出力できます。

または、sysinternals のプロセス エクスプローラーを使用できます。

リモート クライアント マシンであるため、これらすべてが不可能な場合は、userdump をインストールします。これにより、さらに分析するために送信できるダンプ ファイルが作成されます。顧客が正しいパラメータで userdump を呼び出すためのバッチ ファイルを作成できます。Userdump は Microsoft のツールで、Microsoft の Web ページからダウンロードできます。

于 2009-08-01T20:24:56.160 に答える
4

無限ループの場合は、デバッガーを接続してブレークを押してみてください。WinDbgはこれに理想的です。

この手法は、ループが何度も繰り返されているが、最終的には残りのコードを続行する場合にも機能します。良いサンプルを得るために、手順を繰り返すのに数分を費やすことが可能です。

このテクニックは私を数回節約し、ハングしたアプリケーションにもうまく機能します:)

于 2009-08-01T13:52:39.000 に答える
4

可能であれば、プロセス ダンプを取得し、スタック トレースを調べます。
私はそれをやったことがありませんが、VS/WinDbg と SOS (Son of Strike) で動作するはずです。ここにそれに関するブログ記事があります。

于 2009-08-01T11:54:20.567 に答える
2

それらのクライアントに非常に徹底的にインタビューする必要があります。これは必ずしも簡単なことではありませんが、問題を絞り込むための唯一の方法です。

その後、慎重にトレースを追加し、重要なポイントでフラッシュする (またはオートフラッシュを設定する) ことを忘れないでください。

しかし、トレースの遅延が追加されるため、微妙なタイミングの問題になる可能性があります...

于 2009-08-01T12:20:53.437 に答える
2

どこがタイトループなのかを理解する必要があります。その時点でクライアントはソフトウェアで何をしていますか? そもそもソフトウェアは何をするのですか?

コードに多くのログを追加し、クライアントにすべてのログを有効にしたコピーを提供して、問題が発生している場所を追跡することを検討することをお勧めします。

于 2009-08-01T11:53:26.840 に答える
2

postsharpで既存のコードベースに導入できるlog4netのようなロガーを使用します。すべてのメソッドのエントリと終了をログに記録します。これにより、問題のあるメソッドを見つけることができます。それでも必要な場合は、ログを改善できます。

私はそこでの経験はありませんが、これはvb.netでも機能しているようです。たぶん、この記事はあなたを少し助けます。

于 2009-08-01T11:54:55.497 に答える
1

たとえば、バックグラウンド スレッドが UI を更新しようとした場合など、シングルコア CPU とマルチコア CPU の動作が異なるという問題が発生する可能性があります。

(そして、バックグラウンド スレッドと UI スレッドを明確に分離せず、マルチコア CPU が主流になったときに問題を引き起こした暗黒時代にアプリを書いたことを認めます。解決策は、アプリをシングル コアに制限するために SetProcessAffinity を呼び出すことでした)。

その場合は、100% の CPU が特殊な種類の CPU でのみ発生するかどうか、および SetProcessAffinity を使用して問題が解決するかどうかを確認する必要があります。存在する場合は、コード内のどこを探すべきかがわかります。

于 2009-08-01T12:37:27.780 に答える
0

スレッドの問題でしょうか?「断続的に失敗する」と考えさせられます。プログラムは、リモーティング/DCOM/ソケットなど、外部からシグナル/メッセージを受信しますか? このようなメッセージに関連する進捗情報は、ユーザー インターフェイスに表示されますか?

私は常に多くの ASSERT を使用しているため、スレッド化の問題を検出したことがあります。XML-RPC を介して受信されたメッセージの先頭には、次のようなサニティ チェック ASSERT がありました。

"<?xml " 

ASSERT は、メッセージのメモリの上書きをキャッチしました。調べてみると、これはクリティカル セクションにロックがないことが原因であることが判明しました。この検出が可能になったのは、問題が ASSERT によって非常に早期に検出された (そして検出されるのに十分な頻度で発生した) ためです。

これはあまり具体的または指示されたアドバイスではありませんが、私の提案は、スレッドの問題に影響を受ける可能性のある場所に ASSERT を追加することです。

ASSERT の起動は、必ずしもプログラムの中止やメッセージ ボックスのスローを意味するわけではないことに注意してください。ASSERT は、代わりにログ ファイルにリダイレクトできます。これには、ASSERT の起動時の完全なスタック トレースが含まれます。

于 2009-08-02T02:44:33.927 に答える