Process Explorer / Handle / VMMap実践 ── ハング・リーク・「ファイルが使用中」を今この瞬間の状態から追う

· 更新日: · · Sysinternals, Process Explorer, VMMap, ハンドルリーク, メモリリーク, 障害調査, Windows, 長期稼働

「月曜の朝に再起動すれば直るんです」── 装置連携アプリの保守相談で、何度も聞いたセリフです。稼働直後は快調なのに、木曜あたりから画面の切り替えがもたつき、金曜の夕方にはボタンを押しても数秒返ってこない。たまに「ハンドルが無効です」という見たこともないエラーが出る。そして再起動すると、何事もなかったように直る。こうなるともう運用は「毎週再起動」で固定され、根本原因は誰も知らないまま数年が過ぎます。

この種の症状は、ログをいくら眺めても原因にたどり着けません。必要なのは「今この瞬間、そのプロセスが何をどれだけ抱え込んでいるか」を直接見ることです。前回の「Process Monitor(ProcMon)実践ガイド」では、操作の時系列を記録するProcMonを扱いました。今回はその続編・Sysinternals実践の第2弾として、状態を見る側のツール ── Process ExplorerHandleVMMap ── を、長期稼働アプリの三大症状「だんだん重くなる」「ファイルが消せない」「ハングした」に沿って整理します。

1. まず結論

  • ProcMonが「履歴」、Process Explorerは「現在」です。Process Explorerは、各プロセスが開いているハンドルと読み込んだDLLを一覧・検索できるツールで、DLLバージョン問題やハンドルリークの調査に向くと公式も明言しています。1
  • 「ファイルが消せない・差し替えられない」はFind Handle or DLL(Ctrl+F)が最短です。パスの一部で検索すれば、そのファイルを掴んでいるプロセスが数秒で特定できます(3章)。
  • 「ハングした」はプロセスのプロパティ→Threadsタブでスレッドのスタックを見ます。ただしシンボル設定(dbghelp.dllとシンボルパス)をしないとアドレスの羅列しか出ません(4章)。12
  • 「だんだん重くなる」はカラムを足して傾きを見ます。Handle Count・USER Objects・GDI Objects・Private Bytesの4つを追加し、時間を置いて増え続けるものを探します。GDI/USERオブジェクトにはプロセスごとの上限があり、達すると描画やウィンドウ作成が壊れ始めます(5章)。3
  • CLI版のhandle.exeはスクリプトによる定点観測に向きます。handle -s -p <プロセス> で種類別のハンドル数を定期記録できます。-c によるハンドル強制クローズは公式が不安定化を警告しており、基本使いません。4
  • 「Private Bytesが増え続ける」の内訳はVMMapで割ります。Heapならネイティブ、Managed Heapなら.NET、と犯人の土俵を先に決めてから専用ツールに進みます(6章)。5
  • プロセスではなくOS全体のメモリが怪しいときはRAMMapです。6 クラッシュならProcDumpでダンプ採取(「Windowsクラッシュダンプ収集入門」)に切り替えます。
  • どのツールもインストール不要で、Sysinternals Liveから直接実行もできます。オフラインの装置PCにも持ち込みやすい一方、シンボルだけは事前準備が要ります(8章)。7

2. Process Explorerの基本 ── 管理者実行・タスクマネージャー置き換え・画面の読み方

Process Explorerはインストール不要で、ZIPを展開して procexp.exe(64bitなら自動的にprocexp64が動きます)を実行するだけです。1 他ユーザーのプロセスやサービスの中身まで見るツールなので、調査のときは必ず「管理者として実行」します。一般権限で起動すると、肝心のプロセスに限って「アクセスが拒否されました」になり、スタックもハンドルも見えません。

調査担当のマシンでは、Options → Replace Task Manager を有効にしておくと、Ctrl+Shift+Escやタスクバーからのタスクマネージャー呼び出しがそのままProcess Explorerに置き換わります。「とっさのときに使い慣れたツールが開く」効果は地味に大きく、当社でも開発機は全台置き換えています(元に戻すのも同じメニューです)。

画面はプロセスツリーが上、選択したプロセスの詳細が下の2ペイン構成です。下ペインはView → Lower Pane ViewでHandlesビュー(開いているハンドルの一覧)とDLLsビュー(読み込んだDLLとメモリマップトファイルの一覧)を切り替えます。1 まず覚えるべきは行の色の意味です(Options → Configure Colorsで確認・変更できます)。

色(既定) 意味
新しく起動したプロセス(既定では約1秒間)
終了しつつあるプロセス
薄い青 自分と同じユーザーアカウントのプロセス
ピンク サービスをホストするプロセス
パックされた(圧縮・難読化された)実行ファイルの疑い
濃い灰色 サスペンドされたプロセス

「一瞬だけ緑のプロセスが生まれてすぐ赤くなって消える」が延々と繰り返されている、といった異常はツリー表示と色分けだけで見つかります。プロセスの親子関係がツリーで見えるので、「このconhost.exeは誰の子か」「アプリを起動しているのはサービスかタスクスケジューラか」も一目で分かります。

3. 「ファイルが使用中で消せない」── Find Handle or DLLで犯人を特定する

「ログファイルが削除できない」「アップデートしようとしたらexeが使用中」「USBメモリが安全に取り外せない」── この症状の調査は、Find → Find Handle or DLL(Ctrl+F)で終わります。ファイル名やフォルダー名の一部(例: report.csvD:\Data)を入力して検索すると、その名前を含むハンドルを開いているプロセス、またはそのDLLを読み込んでいるプロセスが一覧されます。1 結果の行をクリックすれば、上ペインで該当プロセスが選択され、下ペインで該当ハンドルがハイライトされます。

見つけた後の対処は「そのプロセスを正しく終了させる」が正攻法です。Process Explorer上でハンドルを右クリックしてClose Handleで強制クローズすることもできますが、後述のhandle -cと同じ理由で本番では推奨しません。なお検索できるのは名前付きのオブジェクトだけで、名前なしのイベントやスレッドハンドルはヒットしない点は覚えておいてください。

DLLsビューは「どの場所のどのバージョンのDLLを実際に読み込んだか」の確認にも使います。「古いDLLを掴んでいた」「配置したはずの修正版が読まれていない」というDLLバージョン問題の確認は、この画面がProcMonでのロード順調査(前編5.2節)と対になります。

そもそも「使用中のexe/DLLをどう安全に差し替えるか」は、調査ではなく設計の問題です。同日公開の姉妹記事「使用中のexe/DLLをどう差し替えるか」で、Restart Managerを含む差し替え設計を扱っているので、更新機構を作る側の方はそちらへどうぞ。

4. 「ハングした」── Threadsタブでスレッドのスタックを読む

ウィンドウが白くなって応答なし。強制終了する前に、プロセスをダブルクリックしてプロパティを開き、Threadsタブを見てください。スレッドごとのCPU使用率・サイクル数・開始アドレスが並び、スレッドを選んでStackボタンを押すと、そのスレッドが今どの関数の呼び出し途中で止まっているかが表示されます。ハングの大半は「UIスレッドが何かを待っている」なので、スタックの上のほうに WaitForSingleObjectEnterCriticalSection、同期的なネットワーク・シリアルI/O待ちが見えれば、それが直接原因です。

ただし、シンボルを設定していないとスタックはアドレスと モジュール名+0x1234 の羅列になり、ほぼ読めません。Options → Configure Symbols で次の2つを設定します。

Dbghelp.dll path:
  C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\dbghelp.dll
  ※ WinDbg(Debugging Tools for Windows)に含まれるものを指定する

Symbols path:
  srv*C:\Symbols*https://msdl.microsoft.com/download/symbols
  ※ C:\Symbols はローカルキャッシュ。2回目以降はここから読まれる

ポイントは2つあります。まず、System32にある既定のdbghelp.dllはシンボルサーバーからのダウンロードに対応していないため、WinDbg付属のものを指す必要があること。そして公式ドキュメントにあるとおり、シンボルサーバーを使う場合は、指定したdbghelp.dllと同じ場所にsymsrv.dllが存在している必要があることです(WinDbgのインストールフォルダーなら両方揃っています)。1 シンボルパスの srv*キャッシュ*サーバーURL という書式と、Microsoftのパブリックシンボルサーバー https://msdl.microsoft.com/download/symbols はWinDbgと共通の仕組みです。2 自社アプリのスタックを読むには自社ビルドのPDBも必要なので、シンボルパスにPDB置き場のフォルダーをセミコロン区切りで足しておきます。

.NETアプリの場合、Threadsタブのスタックはネイティブフレーム中心で、マネージドのメソッド名は正確に出ないことがあります。マネージドのハング・デッドロックを本気で追うなら、ハング中にダンプを採ってWinDbg + SOSで見るのが確実です(「WinDbg + SOSでクラッシュダンプを読む」)。Threadsタブは「その場で3分で当たりを付ける」ツール、ダンプは「持ち帰って確定させる」ツールという役割分担です。なおThreadsタブのKill/Suspendボタンは、本番プロセスに対しては押さないでください。観察のつもりが介入になります。

5. 「だんだん重くなる」── ハンドル数・USER/GDIカラムとhandle.exeでリークを監視する

長期稼働で劣化するアプリの定番の原因が、ハンドル・GDI/USERオブジェクト・メモリのリークです。Process Explorerは監視ツールとしても優秀で、View → Select Columns から次のカラムを追加します。

  • Process Performanceタブ → Handle Count(カーネルオブジェクトのハンドル数)
  • Process Memoryタブ → Private BytesVirtual SizeUSER ObjectsGDI Objects

見るのは絶対値ではなく傾きです。健全なアプリはハンドル数が操作に応じて増減しつつ一定の範囲に収まりますが、リークしていると「操作のたびに増えて、二度と減らない」右肩上がりになります。1時間おき、あるいは朝夕でスクリーンショットを残すだけでも、翌日には傾向が分かります。GDIオブジェクトとUSERオブジェクトにはプロセスごとの上限(既定では1万個、レジストリのGDIProcessHandleQuota等で変更可能)とセッション全体の理論上限65,536個があり、上限に達するとペンやブラシの作成、ウィンドウの作成が失敗し始めます。3 「金曜になると画面の描画が化ける」の正体は、たいていこれです。

GUIを開けない環境やスクリプトでの定点観測には、CLI版のhandle.exeを使います。ハンドルの一覧・検索を行うコマンドラインツールで、管理者権限が必要です。4

:: このファイル/フォルダーを誰が掴んでいるか(名前の部分一致で検索)
handle.exe /accepteula report.csv
handle.exe D:\Data

:: ファイル以外も含む全種類のハンドルを、プロセス名を絞ってダンプ
handle.exe -a -p MyEquipApp

:: 種類別のハンドル数を集計 ── リークの定点観測はこれをログに残す
handle.exe -s -p MyEquipApp.exe >> C:\Logs\handles_%date:~0,4%%date:~5,2%%date:~8,2%.log

-s の出力(Event: 1523、File: 88、…という種類別の集計)をタスクスケジューラで1時間ごとに追記しておけば、リモート保守しかできない装置PCでも「どの種類のハンドルが1日にいくつ増えるか」が数字で取れます。種類が分かれば容疑者は一気に絞れます。Eventならイベントの解放漏れ、Fileなら閉じ忘れ、Threadならスレッド終了後のハンドル放置、という具合です。

なお -c オプションで指定ハンドルを強制クローズできますが、公式ドキュメント自身が「ハンドルを閉じるとアプリケーションやシステムが不安定になり得る」と警告しています。4 ロック解除の応急処置としても、本番では基本的に使わない、が当社の運用です。「どの種類がリークしているか」まで分かった後、「どのコードが確保したか」を特定する手順は「産業用カメラ長期稼働クラッシュ調査 - ハンドルリーク編」と「Application Verifierで異常系テストの土台を作る」に続きます。

6. VMMap ── 「Private Bytesが増え続ける」の内訳を割る

ハンドルは横ばいなのにPrivate Bytesだけが増え続ける ── そのときに開くのがVMMapです。プロセスの仮想メモリと物理メモリ(ワーキングセット)を分析するツールで、コミット済み仮想メモリを種類別に分解して見せてくれます5 起動して対象プロセスを選ぶと、上段に色分けされたサマリー、下段に詳細なメモリマップが出ます。主要な分類はこう読みます。

分類 中身 増え続けるときの典型的な犯人
Image EXE/DLL本体 プラグインDLLのロードしっぱなし
Heap ネイティブヒープ(new/malloc/HeapAlloc) C/C++コード、装置SDK、相互運用の解放漏れ
Managed Heap .NETのGCヒープ マネージドの参照リーク(イベントハンドラー等)
Private Data VirtualAllocによる直接確保など 画像フレームバッファ、SDK内部バッファ
Stack スレッドのスタック スレッドの作りっぱなし
Shareable / Mapped File 共有メモリ・マップされたファイル プロセス間連携のセクション解放漏れ

使い方の型は「F5でスナップショットを更新しながら、問題の操作を繰り返し、どの分類が増えるかを見る」です。VMMapはスナップショットの比較とタイムライン表示、結果のエクスポートに対応しているので5、「測定100回で Heap が 40MB 増、Managed Heap は横ばい」といった証拠がその場で取れます。ここで土俵が決まれば、あとは専用ツールの出番です。Managed Heapなら.NET側の調査(「PerfViewとdotnet-traceで「遅い」を特定する」)、Heap/Private Dataならネイティブ側の調査(Application Verifierやダンプ解析)に進みます。この切り分けをせずにいきなりGCを疑って数日溶かすのが、.NET+ネイティブSDK構成の装置アプリで最もよくある回り道です。

32bitプロセスでは断片化も観察対象です。Fragmentation Viewでアドレス空間の空きの散らばりが見え、Freeの合計は数百MBあるのに最大の連続空き(Largest)が数十MBしかない、という状態が可視化されます。「メモリは空いているはずなのにOutOfMemory」「大きな画像バッファの確保だけ失敗する」の正体はたいていこれで、対策(64bit化、バッファの再利用設計)の根拠資料になります。

プロセス単位ではなくOS全体のメモリが怪しい(どのプロセスも太っていないのにメモリ不足になる)ときは、物理メモリ全体の使途をタブ別に見せてくれるRAMMapに切り替えます。ファイルキャッシュ・ドライバー・カーネルの使用量まで見えるので、「アプリ以外の犯人」はこちらで探します。6

7. ケーススタディ ── 「毎週金曜に重くなる装置PC」を切り分ける

冒頭の装置PCを、ここまでの道具で実際に切り分けるとこうなります。月曜朝に再起動する運用なので、金曜は「稼働5日目」。つまり時間に比例して増える何かがある、が初期仮説です。

  1. 水曜あたりにProcess Explorerを置き、カラムを仕込む。Handle Count・USER Objects・GDI Objects・Private Bytesを追加し、対象プロセスの値を記録します。あわせて handle -s -p 対象アプリ.exe の毎時ログをタスクスケジューラに登録します(5章)。
  2. 翌日、傾きを見る。このケースではHandle Countが1日で約2万増、種類別ログではEventハンドルが単調増加していました。Private BytesとGDI/USERはほぼ横ばい。この時点で「カーネルオブジェクト(イベント)の解放漏れ」に絞れます。
  3. Handlesビューで現物を見る。下ペインのHandlesビューをType順に並べると、名前なしのEventが数万個。名前がないのでFind Handleでは追えませんが、種類と増加ペースが分かれば十分です。測定周期(このケースでは装置のポーリング1回につき2個)との対応から、通信ライブラリの待機イベントの解放漏れという仮説が立ち、コードレビューで確定しました。確保箇所をツールで特定するなら、ここからApplication Verifierや!htraceの出番です。
  4. もしPrivate Bytesが増えていたら、3の代わりにVMMapで内訳を割り(6章)、Heapならネイティブ、Managed Heapなら.NETの調査に分岐します。
  5. もしどの数字も横ばいでハングだけするなら、Threadsタブでスタックを見て(4章)、待ち先を特定します。

ポイントは、修正前に「グラフの傾き」という証拠を確保しておくことです。修正後に同じ測定をして傾きがゼロになったことを示せば、「直りました」を数字で報告できます。再現待ちが数日単位の長期稼働問題では、この測定の仕込みこそが調査の本体です。

8. 本番PCへの持ち込みと運用の注意 ── Sysinternals Live・EULA・オフラインのシンボル

Sysinternalsツールはいずれもインストール不要のスタンドアロン実行ファイルで、ZIPをUSBメモリで持ち込めばそのまま動きます。初回起動時にEULAへの同意ダイアログが出るので、無人実行やスクリプトからは /accepteula スイッチで同意を明示します。ネットワークが使える環境なら、Sysinternals Liveというサービスで、ダウンロードせずに https://live.sysinternals.com/procexp.exe のようなURLや \\live.sysinternals.com\tools\<ツール名> のUNCパスから直接実行できます。7 「今すぐこの1台で見たい」ときの最短ルートです。

オフラインの装置PCで引っかかるのはシンボルです(4章のスタック表示が使えない)。対処は2つで、(1)インターネットに接続できる開発機で同じOSビルドに対してシンボルを解決させ、ローカルキャッシュ(C:\Symbols)ごと装置PCにコピーして、シンボルパスをローカルフォルダーだけにする。(2)スタック解析はあきらめて、現地ではダンプ採取(ProcDump)と数値記録に徹し、開発機に持ち帰って解析する。確実なのは(2)で、ダンプの採り方は「Windowsクラッシュダンプ収集入門」にまとめてあります。

最後に運用面です。Process ExplorerやVMMapによる観察は低負荷・低リスクですが、プロセスのKill/Suspend、スレッドのKill、Close Handle、handle -c といった介入の操作は本番では原則禁止にしてください。前編のProcMonと同じく、実施は通常の変更作業と同じ承認プロセスに乗せ、「いつ・誰が・何を観察し、何は操作しないか」を決めてから臨むのが安全です。

9. 実務の定石(判断表)

症状 使うツール 見る場所
だんだん重くなる・数日で不安定になる Process Explorer Handle Count / USER・GDI Objects / Private Bytesカラムの傾き(5章)
ファイルが削除・差し替えできない Process Explorer / handle.exe Find Handle or DLL(Ctrl+F)でパス検索 → 掴んでいるプロセス(3章)
ハング・応答なし Process Explorer プロパティ → Threadsタブ → スレッドスタック(要シンボル、4章)
Private Bytesが増え続ける VMMap Heap / Managed Heap / Private Dataのどれが増えるか(6章)
どのプロセスも太っていないのにメモリ不足 RAMMap Use Counts・File Summaryで物理メモリの使途6
クラッシュする・例外で落ちる ProcDump + WinDbg ダンプ収集WinDbg + SOS
CPUをどこで使っているか・.NETのGC PerfView / dotnet-trace 「遅い」の定量調査
操作の時系列(どのファイルを・いつ・どの順で) Process Monitor 前編記事

10. まとめ

  • ProcMonが「操作の履歴」を記録するのに対し、Process Explorer / Handle / VMMapは「今この瞬間の状態」を見るツールです。長期稼働アプリの調査では両方が必要になります。
  • 「ファイルが消せない」はFind Handle or DLL(Ctrl+F)で数秒、「ハングした」はThreadsタブのスタックで当たりを付けます。スタックを読むにはdbghelp.dll(symsrv.dll同梱の場所)とシンボルパスの設定が前提です。
  • 「だんだん重くなる」はHandle Count・USER/GDI Objects・Private Bytesのカラムを追加して傾きを見ます。handle -s の定期ログなら、GUIを開けない装置PCでも数字が取れます。
  • Private Bytesの増加はVMMapでHeap(ネイティブ)/ Managed Heap(.NET)/ Private Dataに切り分けてから、専用ツールに進みます。32bitプロセスなら断片化も疑います。
  • handle -cやClose Handleによる強制クローズは、公式が警告するとおり不安定化のもとです。本番では観察に徹し、介入はしない・するなら承認を通す、を徹底してください。
  • ツールはスタンドアロンで持ち込みやすく、Sysinternals Liveなら直接実行もできます。オフライン環境ではシンボルの事前キャッシュか、ダンプの持ち帰りで補います。

関連記事

関連する相談領域

合同会社小村ソフトでは、長期稼働で劣化する業務アプリ・装置連携アプリのリーク調査、ハング・「ファイルが使用中」といった現場障害の原因解析、証拠採取手順の整備と再発防止の改修を扱っています。

参考リンク

  1. Microsoft Learn, Process Explorer - Sysinternals. Process Explorerがプロセスの開いているハンドルと読み込んだDLL・メモリマップトファイルを2ペイン(handleモード/DLLモード)で表示すること、特定のハンドルやDLLを持つプロセスを検索できること、DLLバージョン問題やハンドルリークの追跡に有用であること、シンボルサーバー利用時はdbghelp.dllと同じ場所にsymsrv.dllが必要であること、Sysinternals Liveから直接実行できることについて。  2 3 4 5 6

  2. Microsoft Learn, Microsoft Public Symbol Server. Microsoftパブリックシンボルサーバーのシンボルパスがsrvローカルキャッシュhttps://msdl.microsoft.com/download/symbolsの書式で指定できること、ダウンストリームストア(ローカルキャッシュ)には一度アクセスしたシンボルだけが保存され、2回目以降はローカルから読まれることについて。  2

  3. Microsoft Learn, GDI Objects. GDIハンドルにセッションあたり理論上限65,536個があること、プロセスごとの既定の上限が存在しレジストリのGDIProcessHandleQuota(256〜65,536の範囲)で変更できることについて。  2

  4. Microsoft Learn, Handle - Sysinternals. handle.exeが開いているハンドルの情報を表示するコマンドラインツールで管理者権限が必要なこと、名前の部分一致検索、-aで全種類のハンドルを対象にすること、-pによるプロセスの絞り込み、-sによる種類別ハンドル数の集計、-cでハンドルを閉じられるが「アプリケーションやシステムの不安定化を招き得る」と警告されていることについて。  2 3

  5. Microsoft Learn, VMMap - Sysinternals. VMMapがプロセスの仮想・物理メモリ分析ツールであり、コミット済み仮想メモリの種類別の内訳と各種類に割り当てられた物理メモリ(ワーキングセット)を表示すること、フィルタと更新(スナップショット)機能、データのエクスポートとコマンドラインオプションによるスクリプト化に対応することについて。  2 3

  6. Microsoft Learn, RAMMap - Sysinternals. RAMMapがOS全体の物理メモリ使用状況を分析するツールで、Use Counts(種類別集計)、Processes(プロセスのワーキングセット)、File Summary(RAM上のファイルデータ)などのタブで使途を表示すること、スナップショットの保存・読み込みに対応することについて。  2 3

  7. Microsoft Learn, Sysinternals. Sysinternals Liveがツールをダウンロードせずに実行できるサービスであり、live.sysinternals.com/<ツール名>のURLまたは\\live.sysinternals.com\tools\<ツール名>のパスで直接実行できること、live.sysinternals.comでツール一覧を参照できることについて。  2

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

タスクマネージャーがあるのに、Process Explorerをわざわざ使う理由は何ですか?
タスクマネージャーでは「どのプロセスがどのファイルやオブジェクトを開いているか」「各スレッドが今どのコードで止まっているか」が見えないからです。Process Explorerはプロセスごとのハンドル・DLLの一覧、名前でのハンドル検索(Ctrl+F)、スレッドスタックの表示までできるので、「ファイルが消せない」「ハングした」の調査がタスクマネージャーとは別次元になります。ハンドル数やUSER/GDIオブジェクト数のカラムを追加すれば、リークの監視ツールとしても使えます。OptionsメニューのReplace Task Managerを有効にすると、タスクマネージャーの呼び出しがProcess Explorerに置き換わるので、調査担当のマシンでは置き換えてしまうのが実務的です。
handle.exeの-cオプションでハンドルを閉じれば、ファイルのロックをすぐ解除できますか?
技術的には可能ですが、本番環境では基本的に使わないでください。公式ドキュメント自体が「ハンドルを閉じるとアプリケーションやシステムが不安定になり得る」と警告しています。プロセスの内部状態を無視して外からハンドルを奪うため、そのプロセスが後で同じハンドルを使った瞬間に、別のオブジェクトを指していて誤動作する(ハンドル値の再利用)という最悪の事故もあり得ます。正攻法は、掴んでいるプロセスを特定して正しく終了させることです。使用中のexeやDLLを差し替えたいという文脈なら、Restart Managerなどの設計的な解決を検討してください。
Private Bytesが増え続けています。最初に何をすべきですか?
対象プロセスをVMMapで開き、増えているのがどの分類かを見るのが最初の一手です。Heapが増えるならmalloc/new/HeapAllocによるネイティブリークの疑いが濃く、装置ベンダーのSDKやC++/CLI・相互運用のコードが容疑者になります。Managed Heapが増えるなら.NETのマネージドヒープの問題なので、GCが回収できない参照の調査(イベントハンドラーの解除漏れなど)に進みます。Private Data(VirtualAlloc直接確保)が増える場合は、画像バッファのような大きなブロックを確保するコードやSDKを疑います。切り分けができてから、それぞれ専用のツール(WinDbg、PerfViewなど)に進むと調査が迷子になりません。
オフラインの装置PCでは、Threadsタブのスタックがアドレスの羅列になって読めません。どうすればよいですか?
シンボル(PDB)をダウンロードできないためで、対処は「シンボルを持ち込む」か「ダンプを持ち帰る」の2択です。持ち込む場合は、インターネットに接続できる開発機で同じOSビルド・同じアプリ構成に対してシンボルを一度解決させ、ローカルキャッシュフォルダー(例: C:\Symbols)ごと装置PCへコピーし、シンボルパスをそのローカルフォルダーだけにします。持ち帰る場合は、ハング中にダンプを採取して開発機のWinDbgで解析するほうが確実で、マネージドアプリのスタックを正確に読みたいときもこちらが向いています。自社アプリのPDBはビルドごとに保管しておくことが大前提です。
Process ExplorerやVMMapを本番PC・装置PCに入れても問題ありませんか?
いずれもインストール不要のスタンドアロン実行ファイルで、レジストリ登録やサービス常駐なしに動くため、持ち込みのハードルは低いツールです。初回起動時にEULAへの同意が必要で、スクリプトから使う場合は/accepteulaスイッチで同意を明示できます。ネットワークが使える環境なら、Sysinternals Live(https://live.sysinternals.com)からダウンロードせずに直接実行することもできます。ただし観察は低リスクでも、プロセスのKill/Suspend、スレッドのKill、ハンドルの強制クローズといった「介入」の操作は事故に直結するので、本番では観察と記録に徹し、通常の作業承認プロセスに乗せて実施してください。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る