.NET Framework 2.0以降でのアプリケーションのデバッグ

顧客側での.NETアプリケーションのデバッグ、およびコードの最適化に関する一連の記事を始めたいと思います。 この点で、システムを少し準備する必要があります。 この記事では、アプリケーションをデバッグするためのさまざまなツールについて説明します。CLRの説明が必要な場合は、その詳細について説明します。



公益事業



これらすべてが個別の仮想マシンにインストールされ、メインOSを詰まらせないことが便利です。メインOSは.NETおよびエンターテイメントでのアプリケーション開発にのみ使用します。



.NETアプリケーションのデバッグ



アプリケーションを開発するとき、開発者は通常、完全に制御できるマシンで作業し、さまざまなユーティリティを使用できます。 デバッグ用に、コードをステップ実行し、変更してコンパイルする機能を備えた開発環境があります。 問題なく、いつでもアプリケーションを一時停止して、再起動できます。 ただし、顧客のサーバーでは、システムユーザーに影響を与えることなく、段階的なデバッグのためにアプリケーションを一時停止することはほとんど不可能です。 一般に、顧客のサーバーでアプリケーションをデバッグすると、通常は問題をできるだけ早く解決する必要があります。 シンプルなサービスでは、顧客はお金を失い、顧客は去り、単純な生産サイクルがあり、他の問題が発生する可能性があります。 問題が発生した場合は、一時的に解決するための対策を講じることを強くお勧めします。 これには、アプリケーションのリロード、機能の制限、および状況に対する他のソリューションが含まれる場合があります。

いくつかの問題が発生する可能性があります:アプリケーションのフリーズ、デッドロック、未処理または致命的な例外、データ損失、パフォーマンスの問題、リソースとメモリリーク、不正な機能。 これらの状況はすべて、特定のユーザーだけでなく、システムのすべてのユーザーに影響を与えます。

アプリケーションで問題を引き起こす主な理由は、環境の違い(ハードウェア、ソフトウェア、構成の違い)、および他のシステムとの相互作用です。

クライアント側でアプリケーションをデバッグするのがなぜ難しいのですか? 標準ツールを使用することはできません。サーバーにアクセスすることは困難または不可能であり、問​​題は非常にまれにしか発生しないか、顧客側にのみ発生します。

アプリケーションの種類に応じて、顧客にアプリケーションをインストールする前にこれらの手順を実行できます。

サーバーアプリケーション:



クライアントアプリケーション:



リスクを最小限に抑えるために、顧客に表示される前にエラーを見つけて修正し、さまざまな状況を解決し、Visual Studioの標準とサードパーティのNUnit NCoverの両方で自動テストを行うことをお勧めします。

問題が発生した場合、できるだけ多くの情報を収集することが重要です。これは、エラーの調査と修正に役立ちます。



管理アセンブリアセンブリ構造



あまり詳細には触れません。 それらはさまざまなバージョンで簡単にアクセスできます。さらに使用するものについてのみ説明し、追加の情報源に注意します。

.NET実行可能ファイルは、すべてのWindowsアプリケーションに標準の通常のMS-DOSおよびCOFFヘッダーで始まります。

最初のデータセクションには、CLRヘッダーとデータが含まれます。

ildasm.exe

最初のセクションには属性CNT_CODE、MEM_EXECUTE、MEM_READがあり、ランタイムに実行されるコードがセクションに含まれていることをローダーに示すことに注意してください。 インポートテーブルでは、アプリケーションを実行している場合の呼び出し「_CorExeMain」を確認できます。 ランタイム環境のメインモジュールのmscoree.dllに実装されています。

  mscroree.dll

詳細については、「 アンマネージAPIリファレンス 」を参照してください。

これらのセグメントの後には、アプリケーション自体のILコードが続きます。 コンパイル結果は中間言語コード(MSIL)です。 これは、プロセッサに依存しない言語です。ネイティブコードよりも高いレベルの言語です。 仕様はこちらで確認できます。



ILコードの後に​​は、メタデータヘッダー、メタデータ自体、アプリケーションリソースを含む追加セグメント、ネイティブアプリケーションコードが続きます(アプリケーションがマネージC ++で開発された場合)。

実行可能ファイルの構造に関する情報は、標準のildasm.exeユーティリティを使用して取得できます。



WinDbg + SOS、adplus.vbsの探索



この段階で、必要なすべてのアプリケーションを既にインストールして構成していることを願っています(Debug Tools ToolsディレクトリーもPATH環境変数に追加してください)。 このテストプログラムについてさらに調査します。



いくつかのナンセンスを行う独自のアプリケーションを作成することができます(必要です)。 このプログラムで重要なのは(o__O、私はそのような考えに傾いていました)、そして重要なのは、ヒープにいくつかのオブジェクトを作成し、いくつかのメソッドを呼び出し、最終的に誤って例外をスローすることです。 文字を使用してアプリケーションのデバッグバージョンを作成しましょう。

アプリケーションを起動します。 そして、アプリケーションのあるディレクトリにこのコマンドを入力します

adplus -quiet -crash -fullonfirst -pn ApplicationForWinDbg.exe

ApplicationForWinDbg.exeはコンパイル済みのexeです。



コンソールアプリケーションで、任意のキーを押します。 すべてを正しく行った場合、 Crash_Mode__Date_ [DATE] __ Time_ [TIME]フォルダーがデバッグツールがインストールされたディレクトリに表示されます。 [日付][時間]は、ダンプが作成された日付と時刻です。

ダンプを作成し、それを調べ、同時にCLRの内部を理解します。 この記事では詳細な説明は行いません。主なことは、WinDbg + SOSの使用方法を学ぶことです。 詳細は他の記事で。

WinDbgでダンプを開きます。 次のようなものが得られるはずです。

WinDbg

次のコマンドを実行して、WinDbg-SOS拡張機能をダウンロードします。

0:000> .loadby sos mscorwks

ダウンロードの進行状況を確認するには、次のコマンドを実行します。

0:000> !Eeversion

  2.0.50727.3053小売
ワークステーションモード
 SOSバージョン:2.0.50727.3053小売ビルド 


拡張機能がロードされていることを確認し、 ctrl + sを押し、WinDbgが文字をロードするようにアプリケーションへのパスを追加します。 これで調査を開始できます。 アプリケーションにあるスレッドを見てみましょう。

0:000> 〜*

  。  0 Id:e8c.11bc一時停止:1 Teb:7ffde000 Unfrozen
      開始:ApplicationForWinDbg!COM + _Entry_Point <PERF>(ApplicationForWinDbg + 0x284e)(0011284e) 
      優先度:0優先度クラス:32アフィニティ:3
    1 Id:e8c.13f0一時停止:1 Teb:7ffdd000 Unfrozen
      開始:mscorwks!DebuggerRCThread :: ThreadProcStatic(7243237f) 
      優先度:0優先度クラス:32アフィニティ:3
    2 Id:e8c.130c一時停止:1 Teb:7ffdc000 Unfrozen
      開始:mscorwks!スレッド:: IntermediateThreadProc(724c1fcf) 
      優先度:2優先度クラス:32アフィニティ:3 


マネージスレッドを見てみましょう。

0:000> !スレッド

 スレッドカウント:2
 UnstartedThread:0
 BackgroundThread:1
 PendingThread:0
デッドスレッド:0
ホストされたランタイム:いいえ
                                       PreEmptive GC Alloc Lock
        ID OSID ThreadOBJ状態GCコンテキストドメインカウントAPT例外
    0 1 11bc 00529188 a020無効01c903cc:01c91fe8 00524c40 0 MTA
    2 2 130c 00537020 b220有効00000000:00000000 00524c40 0 MTA(ファイナライザー) 


これから、アプリケーションに2つのマネージスレッド(アプリケーションが実行されているメインのマネージスレッドとFinalizerスレッド)があることがわかります。 そして、もう1つのアンマネージmscorwksスレッドがあります!DebuggerRCThread :: ThreadProcStaticデバッガースレッドです。 通信仕様は閉じられ、デバッグ情報、段階的なデバッグ機能などが提供されます。このストリームは、アプリケーションのリリースバージョンを作成するかデバッグバージョンを作成するかに関係なく存在します。

アプリケーションのAppDomainsを見てみましょう。

0:000> !ダンプドメイン

 --------------------------------------システムドメイン:728ed058 LowFrequencyHeap:728ed07c HighFrequencyHeap:728ed0c8 StubHeap: 728ed114ステージ:オープン名前:なし--------------------------------------共有ドメイン:728ec9a8 LowFrequencyHeap :728ec9cc HighFrequencyHeap:728eca18 StubHeap:728eca64ステージ:OPEN名前:なしアセンブリ:0051c920 --------------------------------- -----ドメイン1:00524c40 LowFrequencyHeap:00524c64 HighFrequencyHeap:00524cb0 StubHeap:00524cfcステージ:OPEN SecurityDescriptor:00526198名前:ApplicationForWinDbg.exeアセンブリ:0051c920 [C:\ WINDOWS \アセンブリ\ GAC_32 \ mscorlib \ 2.0.0.0__b77a5c561934e089 \ mscorlib .dll] ClassLoader:0051c990 SecurityDescriptor:005384a8 Module Name 70da1000 C:\ Windows \ assembly \ GAC_32 \ mscorlib \ 2.0.0.0__b77a5c561934e089 \ mscorlib.dll Assembly:0051ca70 [D:\#Projects \ #Active \ TestApplicationbg \ Application Debug \ ApplicationForWinDbg.exe] ClassLoader:0051cae0 SecurityDescriptor:0053d088モジュール名00202c5c D:\#Projects \ #Active \ Test  ApplicationNet \ ApplicationForWinDbg \ bin \ Debug \ ApplicationForWinDbg.exe 


コードが実行されるドメインに加えて、 システムドメイン共有ドメインもあります。 1つは、 共有ドメインのロードと、すべてのユーザードメインのロードとアンロードを担当します。 2番目は、ドメイン中立アセンブラアセンブリのリポジトリとして機能します。 コードはユーザードメインでのみ実行できるため、コードは共有ドメインでは実行されません。

ユーザードメインでは、モジュール-実行可能ファイルdll、exe、その他を確認します。 アセンブラアセンブリには複数のモジュールが含まれている場合がありますが、これらは実行可能ファイルだけでなく、リソースファイルでもあります。 前の例からアセンブリアセンブリcaca70のアドレスを取得し、追加情報を取得します。

0:000> !ダンプアセンブリ0x0051ca70

 親ドメイン:00524c40
名前:D:\#Projects \ #Active \ TestApplicationNet \ ApplicationForWinDbg \ bin \ Debug \ ApplicationForWinDbg.exe
クラスローダー:0051cae0
 SecurityDescriptor:002bed20
  モジュール名
 00202c5c D:\#Projects \ #Active \ TestApplicationNet \ ApplicationForWinDbg \ bin \ Debug \ ApplicationForWinDbg.exe 


モジュール00202c5cに関する情報を見てみましょう。

0:000> !Dumpmodule 0x00202c5c

 名前:D:\#Projects \ #Active \ TestApplicationNet \ ApplicationForWinDbg \ bin \ Debug \ ApplicationForWinDbg.exe
属性:PEFile 
アセンブリ:0051ca70
 LoaderHeap:00000000
 TypeDefToMethodTableMap:00200038
 TypeRefToMethodTableMap:00200048
 MethodDefToDescMap:002000a0
 FieldDefToDescMap:002000b8
 MemberRefToDescMap:002000bc
ファイル参照マップ:00200118
 AssemblyReferencesMap:0020011c
メタデータの開始アドレス:001120e4(1668バイト) 


–mtパラメーターを使用すると、モジュールの型に関する情報も取得できます。

0:000> !Dumpmodule -mt 0x00202c5c

 名前:D:\#Projects \ #Active \ TestApplicationNet \ ApplicationForWinDbg \ bin \ Debug \ ApplicationForWinDbg.exe
属性:PEFile 
アセンブリ:thodTableMap:00200038
 TypeRefToMethodTableMap:00200048
 MethodDefToDescMap:002000a0
 FieldDefToDescMap:002000b8
 MemberRefToDescMap:002000bc
ファイル参照マップ:00200118
 AssemblyReferencesMap:0020011c
メタデータの開始アドレス:001120e4(1668バイト)

このモジュールで定義されているタイプ

       MT TypeDef名
 -------------------------------------------------- ----------------------------
 00203080 0x02000002 ApplicationForWinDbg.Class1
 0020300c 0x02000003 ApplicationForWinDbg.Program

このモジュールで参照されるタイプ

       MT TypeRef名
 -------------------------------------------------- ----------------------------
 71010508 0x01000001 System.Object
 710108ec 0x01000012 System.String
 71014258 0x01000013 System.Console
 71012b38 0x01000015 System.Int32
  0051ca70
 LoaderHeap:00000000
 TypeDefToMe 


コードで定義されているタイプがApplicationForWinDbg.Class1およびApplicationForWinDbg.Programであることを発見しました。 これらのクラスに関する情報は、 EEClassの内部構造に格納されます。 この構造には、インターフェイス、メソッド、フィールドの数、およびそれらの構造などに関する情報が含まれています。

ヒップで何を持っているか見てみましょう:

0:000> !Dumpheap

 アドレスMTサイズ
 01c71000 0052ccc8 12無料
 01c7100c 0052ccc8 12無料
 01c71018 0052ccc8 12無料
 01c71024 71010b10 72     
 01c7106c 71010ba0 72     
 01c710b4 71010c30 72     
 01c710fc 71010cc0 72     
 01c71144 71010cc0 72     
 01c7118c 71010508 12     
 01c71198 710108ec 20     
 01c711ac 71010fb8 28     
 01c711c8 710108ec 160     
 01c71268 710108ec 216     
 01c71340 710110cc 100     
 01c713a4 710113d8 44     
 01c713d0 70fe40bc 80     
 01c71420 710108ec 28     
 01c7143c 710108ec 32     
 01c7145c 710108ec 20     
 01c71470 710108ec 52     
 01c714a4 710108ec 40     
 ……………………………………………………
 01c90398 7101151c 24     
 01c903b0 710108ec 28     
 02c71000 0052ccc8 16無料
 02c71010 70fe40bc 4096     
 02c72010 0052ccc8 16無料
 02c72020 70fe40bc 528     
 02c72230 0052ccc8 16無料
 02c72240 70fe40bc 4096     
 02c73240 0052ccc8 16無料
合計5361オブジェクト
統計:
       MTカウントTotalSizeクラス名
 71013dc0 1 12 System.Text.DecoderExceptionFallback
 71013d7c 1 12 System.Text.EncoderExceptionFallback
 71013ae4 1 16 System.Text.DecoderReplacementFallback
 71013a94 1 16 System.Text.EncoderReplacementFallback
 71014808 1 20 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
 710147b0 1 20 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
 71014724 1 20 System.Text.InternalEncoderBestFitFallback
 71012e50 1 20 System.Security.PermissionToken
 7100e8b8 1 20 Microsoft.Win32.SafeHandles.SafeFileHandle
 71014770 1 24 System.Text.InternalDecoderBestFitFallback
 710143c0 1 24 System.IO.TextWriter + SyncTextWriter
 710127cc 2 24 System.Security.Permissions.SecurityPermission
 71012510 1 24 System.OperatingSystem
 71014290 1 28 Microsoft.Win32.Win32Native + InputRecord
 71013f24 1 28 System.Text.EncoderNLS
 71013c34 1 28 System.IO.Stream + NullStream
 71013990 1 28 System.Text.UTF8Encoding
 71010fb8 1 28 System.SharedStatics
 71013ea4 1 32 System.Text.UTF8Encoding + UTF8Encoder
 71012efc 1 32 System.Security.PermissionTokenFactory
 710122cc 1 32 Microsoft.Win32.Win32Native + OSVERSIONINFO
 710142e4 1 36 System.IO .__ ConsoleStream
 71012eb0 1 36 System.Security.Util.TokenBasedSet
 71012d18 1 36 System.Security.Permissions.FileIOPermission
 710120c8 1 36 System.Int64 []
 710123d4 1 40 Microsoft.Win32.Win32Native + OSVERSIONINFOEX
 7101278c 1 44 System.Security.FrameSecurityDescriptor
 710113d8 1 44 System.AppDomainSetup
 71012874 3 48 System.Security.Permissions.FileIOAccess
 71012494 2 48 System.Version
 71011e38 2 48 System.Reflection.Assembly
 7100e6f4 4 48 System.UInt16
 71012c14 2 56 System.Collections.ArrayList + ArrayListEnumeratorSimple
 71010ec0 1 56 System.Threading.Thread
 71013714 1 68 System.Globalization.CultureTable
 710128bc 3 72 System.Security.Util.StringExpressionSet
 710125b0 2 72 System.Security.PermissionSet
 71010c30 1 72 System.ExecutionEngineException
 71010ba0 1 72 System.StackOverflowException
 71010b10 1 72 System.OutOfMemoryException
 71014608 1 76 System.Text.SBCSCodePageEncoding
 710137a8 5 100 System.Globalization.CultureTableItem
 710110cc 1 100 System.AppDomain
 0052ccc8 7100無料
 71012b38 9108 System.Int32
 710140d4 2 112 System.IO.StreamWriter
 71010a28 6120 System.Text.StringBuilder
 71010508 10120 System.Object
 710136c4 3 144 System.Globalization.CultureTableRecord
 7101291c 6 144 System.Collections.ArrayList
 71010cc0 2 144 System.Threading.ThreadAbortException
 71011a6c 8160 System.RuntimeType
 71011fe4 3 192 System.IO.UnmanagedMemoryStream
 710134e8 3204 System.Globalization.CultureInfo
 71013850 2 256 System.Globalization.NumberFormatInfo
 71012f40 7 392 System.Collections.Hashtable
 7101335c 3 684 System.Byte []
 7101303c 7 1008 System.Collections.Hashtable + bucket []
 71012a88 14 1536 System.Int32 []
 70fe40bc 28 9564 System.Object []
 00203 080 1000 12000 ApplicationForWinDbg.Class1
 7101151c 1022 25376 System.Char []
 710108ec 3160 82600 System.String
合計5361オブジェクト 


答えてみてください、今何行が腰にありますか?

メタデータへのポインターを使用して、ApplicationForWinDbg.Class1クラスに関する情報を取得します。

0:000> !Dumpmt 0x00203080

  EEClass:0020135c
モジュール:00202c5c
名前:ApplicationForWinDbg.Class1
 mdToken:02000002(D:\#Projects \ #Active \ TestApplicationNet \ ApplicationForWinDbg \ bin \ Debug \ ApplicationForWinDbg.exe)
 BaseSize:0xc
 ComponentSize:0x0
 IFaceMapのIFacesの数:0
 VTableのスロット:7 


これで、そのEEClassへのポインターにアクセスでき、その説明が表示されます:

0:000> !Dumpclass 0x0020135c

 クラス名:ApplicationForWinDbg.Class1
 mdToken:02000002(D:\#Projects \ #Active \ TestApplicationNet \ ApplicationForWinDbg \ bin \ Debug \ ApplicationForWinDbg.exe)
親クラス:70da3ef0
モジュール:00202c5c
方法表:00203080
 Vtableスロット:4
総メソッドスロット:5
クラス属性:100000  
 NumInstanceFields:0
 NumStaticFields:0 


メソッドテーブル00203080へのポインタによって、クラスのすべてのメソッドのリストを見てみましょう。

0:000> !Dumpmt -md 0x00203080

  EEClass:0020135c
モジュール:00202c5c
名前:ApplicationForWinDbg.Class1
 mdToken:02000002(D:\#Projects \ #Active \ TestApplicationNet \ ApplicationForWinDbg \ bin \ Debug \ ApplicationForWinDbg.exe)
 BaseSize:0xc
 ComponentSize:0x0
 IFaceMapのIFacesの数:0
 VTableのスロット:7
 --------------------------------------
 MethodDescテーブル
    Entry MethodDesc JIT名
 70f66a70 70de4934 PreJIT System.Object.ToString()
 70f66a90 70de493c PreJIT System.Object.Equals(System.Object)
 70f66b00 70de496c PreJIT System.Object.GetHashCode()
 70fd72f0 70de4990 PreJIT System.Object.Finalize()
 004b0150 00203078 JIT ApplicationForWinDbg.Class1..ctor()
 004b0188 00203060 JIT ApplicationForWinDbg.Class1.Method1(System.String)
 004b01d8 0020306c JIT ApplicationForWinDbg.Class1.Method2(Int32) 


また、例として、 ApplicationForWinDbg.Class1.Method1とそのコンパイル済みコードに関する情報を見てみましょう。

0:000> !Dumpmd 0x00203060

 メソッド名:ApplicationForWinDbg.Class1.Method1(System.String)
クラス:0020135c
 MethodTable:00203080
 mdToken:06000001
モジュール:00202c5c
 IsJitted:はい
 CodeAddr:004b0188 


0:000> !U 0x004b0188

 通常のJIT生成コード
 ApplicationForWinDbg.Class1.Method1(System.String)
 004b0188の開始、サイズ3a
 >>> 004b0188 55 push ebp
 004b0189 8bec mov ebp、esp
 004b018b 83ec0c sub esp、0Ch
 004b018e 894dfc mov dword ptr [ebp-4]、ecx
 004b0191 8955f8 mov dword ptr [ebp-8]、edx
 004b0194 833d142e200000 cmp dword ptr ds:[202E14h]、0
 004b019b 7405 je 004b01a2
 004b019d e8dfa21472 mscorwksを呼び出す!JIT_DbgIsJustMyCode(725fa481)
 004b01a2 90 nop
 004b01a3 8b153020c702 mov edx、dword ptr ds:[2C72030h]( "$")
 004b01a9 8b4df8 mov ecx、dword ptr [ebp-8]
 004b01ac e86feaaa70 call mscorlib_ni + 0x1bec20(70f5ec20)(System.String.Concat(System.String、System.String)、mdToken:060001c9)
 004b01b1 8945f4 mov dword ptr [ebp-0Ch]、eax
 004b01b4 8b4df4 mov ecx、dword ptr [ebp-0Ch]
 004b01b7 e81c36fc70 call mscorlib_ni + 0x6d37d8(714737d8)(System.Console.WriteLine(System.String)、mdToken:060007c8)
 004b01bc 90 nop
 004b01bd 90 nop
 004b01be 8be5 mov esp、ebp
 004b01c0 5dポップebp
 004b01c1 c3 ret 


すべてのリスティングのために記事が長くなることが判明したため、おそらくここで終了します。 継続を待ちます。 そして、すべてのフィールドの目的のより詳細な説明と、次の記事では、他のコマンドについて説明します。



All Articles