Blog株式会社グラニはC#を中心として、ASP.NET、Unity、VR開発を行っています。2017-11-07メモリダンプから.NETのメモリ状態を探りたい.NETこんにちは、@mayukiです。Studioでの可視化によるC#トラブルシューティングというスタックオーバーフローのような問題を調査する方法について触れましたが、今回はダンプを元にメモリ周りの状態を見ていく方法について調べたので少しまとめてみました。長い時間実行するようなアプリケーション(アプリケーションサーバーなど)ではメモリの使用状況やメモリリークなどを調査したいというケースがたまにやってきます。そんなときにはプロセスのメモリダンプを取得して解析することで問題の原因がわかりそう...そんなシチュエーションで役立つかもしれません。addr>ファイナライザースレッドがブロック状態かどうかを調べるAppendixWinDbgでもっと簡単に詳しくファイナライザーの実行を.NETアプリケーションコードから知りたいまとめ前提まずダンプを取得する対象のbitness(64bit/32bit)と解析するマシンのbitnessは合わせておきましょう。合致していない場合であっても頑張れば解析できるとは思うのですが今回はそこに関して詳しくは触れません。32-bitが有効な状態でビルドされている場合、64bitマシン上では32bitで起動するので要注意です。ダンプファイルの取得の仕方に関しては先のエントリーを参照してください。1709の組み合わせです。バージョンによっては若干手順が異なる、利用できない場合があります。(x86)プロセスで動いているもののダンプをとって調べることになった際には次の点に注意してください。https://blogs.msdn.microsoft.com/tess/2010/09/29/capturing-memory-dumps-for-32-bit-processes-on-an-x64-machine/WinDbgでダンプを開くときはWinDbgのbitnessを解析対象プロセスのbitnessに合わせるつまり32bitプロセスをデバッグするにはWinDbg(x86)が必要だということですダンプのみどころダンプをとったはいいものの一体何を見ればいいのかを考える必要があります。メモリ周りと言っても単純にメモリの使用状態を見たいのか、メモリリークを調べたいのかで少し違いますが次のようなものをよく見る感じでしょうか。何が大きく占めているのか、異常に増え続けていそうなものがあるのか?各ジェネレーションごとのサイズなどメモリリークを調べるオブジェクトのルートGCで回収できないのは誰がつかんでいるせいなのか?ファイナライザーの状態ファイナライザースレッドがブロックされていないかファイナライザースレッドがブロックされているとFinalize待ちが溜まるもっとも、メモリダンプをとってメモリ周りを調べるようなシチュエーションでは大抵はリークを疑っているケースがほとんどかと思います。どのツールで解析すれば?さて、ダンプファイルを無事取得でき、見たいところも何となくわかったとしてどうやって調べていけばよいのか...。Studioを利用しましたが今回はそれに2つ加えて、3つの解析ツールをご紹介します。ハードコアデバッガーこれら3つともMicrosoftの提供しているツールで、下に進むにつれ詳細な情報が取れるとふんわりと考えてもらえればよいかと思います。今回WinDbgに関してはコマンドがいろいろあるのでその部分が若干多めな解説です。サードパーティーのツールなどもありますが今回は標準的なツールのみです(最近はdotMemoryもダンプをインポートできるらしいとか)。Studioではないでしょうか?開発環境であれば特に追加のインストールも不要ですしお手軽ですね。限る)ここでは以下の単にオブジェクトを作るだけのプログラムでダンプをとってみたものを解析してみます。Studioでひらくと次のような画面が表示されます。Memory"を選択するとメモリ状態を表示するモードとなります。これでオブジェクトがどのぐらいあり、どのぐらいのメモリを使っているのかという情報を一覧表示できます。いう二つのビューがあります。選択したオブジェクトからルートとなるオブジェクトへのツリー、つまり参照元を表示します(最終的にはGC対象となるルート)。いう順でたどれるよということになります。なくなればGCが回収可能となりますし、逆を言えばここが残っているということは解放できないということでもあります。選択したオブジェクトが参照しているオブジェクトへのツリー、つまり参照先を表示します(選択したオブジェクトが依存しているオブジェクト)。上記の図ではList<A>はA[]を持ち、A[]はAを、AはBを参照しているということがわかります。Typeのカラムでアイコンが表示されるのでクリックすることで個々のオブジェクトを探っていくこともできます。Studioで見れば何となくあれが多いんだなとか、これで開放されてなさそうだなといった情報をつかめる場合が多いでしょう。Studioでは開けないなど、もう少し突っ込んだ状態を調べたくなったら他のツールを検討します。StudioにSOS拡張をロードできたのですがここ最近はそのようなことができなくなっていますDebugDiagを試してみる次はDebugDiagを使ってみましょう。DebugDiagはMicrosoftが提供しているダンプ自動解析ツールです。ダンプファイルを突っ込むとまあまあいい感じにレポートを出してくれるという便利ツールです(それだけではないのですが)。起動すると以下のような画面が表示されます。Analysisで解析を開始します。Explorer(!)で開かれます。レポートには以下のようなものが記録されます。Studioに比べて逆に細かいところは見れないのですが、まとめを出してくれるので大まかに状態の把握をするのには便利ですし、ファイナライゼーションキューの情報なども出せるのはなかなかわるくないのです。このレポート、MHTML形式なうえに微妙に壊れることがあるのが若干難ありですが読めるのであればあまり気にしないことにしましょう。読めないようなものが出てきた場合には...お疲れさまでした...。巨大なダンプファイルの解析にはとても時間がかかるので辛抱も必要です(とはいえWinDbgでもかかります)。ハングやクラッシュを調べるちなみに解析ルールとしてCrashHangAnalysisというクラッシュやハングを解析するルールもあります。Studioでの可視化によるC#トラブルシューティングと同じようにスタックオーバーフローを確認してみましょう。overflowにならなかったため少し変更しています。これをビルドして実行すると無事死亡です。その際作られたダンプファイルをDebugDiagに食べさせて、CrashHangAnalysisをかけてみましょう。overflowという結果が表示されます。レポートにはスレッドのスタックトレースなども出てくるので一発でダメなのがわかりますね。Studioでできるよ]と言われるとそうですねという感じなのですが、GUIでポチポチやって明らかにダメなものを発見できるお手軽解析ツールとして入れて置いておいても良いかなと思います。まあしかしレポートなどが古めかしいの直したいのでオープンソースにしてほしいぞい...。WinDbgを試してみる最後はハードコアなデバッガーWinDbgで解析する方法です。面倒な代わりに詳細な情報を得られるのが特徴です。そもそも.NET用のデバッガーではないというあたりから難易度の高さを誇り、最低限の操作だけ覚えていく感じです。最近Preview版として見た目がよくなったバージョンがリリースされたのですが、本質は変わっていないのでぬるま湯マネージコードマンには相変わらずハードコアです。インストールWinDbgのインストールですが、なんとPreview版ではMicrosoftストアからワンポチでインストールできます。file"で.dmpファイルを選択してダンプファイルを開きます。ダンプファイルを開くと次のような画面になります。その横の入力エリアがコマンド入力欄となっていて、WinDbgであれこれ操作するのはここにコマンドを打ち込んで操作を実行していくことになります。ダンプファイルを開いてもそのままではマネージコードのデバッグはできないのでSOS拡張をロードするところから始まります。SOS拡張をロードするには以下のコマンドを実行してください。clrこの際、LoadLibraryでライブラリが見つからない的なエラーになる場合がありますが、それはbitnessがあっていない、つまり64bitマシンで32bitのダンプを解析しようとしてる場合に出てきます。読み込むDLLを変えれば対応できるはずですが前提にも書いた通りターゲットアプリケーションを64bitにするほうが手っ取り早いのでそうしましょう。CLRの中身が透けて見えるといっても過言ではない代わりに、それ相応の用語が出てくるので何となく押さえておくとはかどります。なんかオブジェクトがあるところ。