Visual Studio 2022のメモリ使用量診断ツールの使い方

はじめに

  • Visual Studio 2022にはアプリケーションの問題を診断するためのプロファイリングツールが付属しています。ここでは、プロファイリングツールに含まれるメモリ使用量を調査するためのツールを紹介します。
  • 使用環境は次の通りです。
    OSWindows 10(64ビット)
    IDEMicrosoft Visual Studio Community 2022(17.6.0)
    言語C#(10.0) + .NET6
    ハードウェアCPU: AMD Ryzen 5 3400G, MEM: 16GB, SSD: 130GB
  • 用語・表記に関して
    • メモリ使用量を調べるツールの名称に関して、リファレンスだと「メモリ使用量(Memory Usage)」「メモリ使用量診断ツール」とありますが、ここでは「メモリ使用量診断ツール」と表記します。
    • メモリ使用量診断ツールの使用方法として「デバッガー統合ツールと非デバッガーツール」と分けられていますが、ここでは「デバッガ統合版」「パフォーマンスプロファイラー版」と表記します。

プロファイリングツール

  • 処理速度の遅延やメモリリーク等の問題を診断するために、Visual Studio 2022には多くの診断ツールが用意されています。
  • 数が多すぎてどれを使えば良いかぱっと分かりませんが、「ツールを使用するタイミング」が参考になります。今回の場合、メモリリークの調査を想定しているので、「メモリリークの疑いを調査する (ネイティブ コード)」の記載があるメモリ使用量診断ツール(Memory Usage)ツールを使用します。
  • このツールでは、実行中のアプリのメモリの状態(断面=スナップショット)の取得や、それらの比較を行うことができます。そのため、事象発生前後のスナップショットを取得・比較することで、増加しているオブジェクトの数や使用メモリ量を特定できます。この結果から、問題の原因となりうる処理部分を絞り込むことができます。
  • メモリ使用量関連のツールとして「.NETオブジェクト割当ツール」(.NET Object Allocation tool)もあります。このツールは、オブジェクトのメモリへの割り当てやガベージコレクション動作の分析に使用するもののようです。このツールでの情報は細かすぎるので、メモリリーク調査の第一段階では、メモリ使用量診断ツールをお薦めします。

メモリ使用量診断ツールの概要

画面と使用イメージ

  • 事象が発生する前後でメモリ使用状態(スナップショット)を取得します。取得したスナップショットやスナップショット同士の比較結果がレポート(ウインドウ)として表示されるので、その内容をもとに原因個所の絞り込みを行っていきます。
  • レポートウインドウでは、スナップショットのオブジェクト数・メモリ使用量を確認できます。比較対象となるスナップショットを選択した場合、そのスナップショットから増減したオブジェクト数・メモリ使用量(相違)を表示できます。選択したオブジェクトの参照元や参照先を確認することもできます。
  • 後述しますが、メモリ使用量診断ツールは2つの起動方法があり、ここではデバッガ統合版の画面イメージを紹介しますが、パフォーマンスプロファイラー版も同様の画面になります。

レポートの種類

  • リファレンスの要約して独自に纏めたレポートの分類です。
    アプリの種類
    .NETアプリ非.NETアプリ
    比較対象
    スナップショット
    なしマネージド型レポート
    (スナップショットの詳細レポート)
    ネイティブ型レポート
    (スナップショットの詳細レポート)
    ありマネージド型レポート
    (スナップショットの相違レポート)
    ネイティブ型レポート
    (スナップショットの相違レポート)
    • 診断対象となるアプリが.NET(.NETによるメモリ管理)か否かや、比較対象となるスナップショットの有無で、レポートを区別しています。
    • 画面構成はどのレポートでも同様ですが、表示項目が微妙に異なります。
  • ここではASP.NET Coreのアプリを想定しているので、以降ではマネージド型レポートを前提として説明します。レポートの種類が変わっても表示される内容は差ほど変わらないので、それほど意識する必要はないと思います。

レポートの項目

  • レポートウインドウは、上段のオブジェクト種類の一覧が表示された領域と、一覧で選択されたオブジェクトの詳細を表示する領域、で構成されます。便宜上、ここでは、前者の領域を「オブジェクト種類一覧」、後者の領域を「オブジェクト種類詳細」と表記します。

オブジェクト種類一覧

  • オブジェクト種類一覧のイメージと項目は次の通りです。
    (「タイプ」「分析情報」タブに分かれていますが、分析情報は使用していないので割愛します。)

    No.項目名説明
    1ベースラインと比較比較対象とするスナップショットを選択できます。何も選択していない場合、相違ではなくそのスナップショットの内容をレポートに表示します。スナップショットが選択された場合、そのスナップショットを基準として増減がレポートに表示されます。
    (相違レポートの場合、自動的にこの項目に直前のスナップショットが選択されます。)
    2種類のフィルター処理名前空間やクラス名等でオブジェクト一覧の表示を絞り込むことができます。
    3マイコードのみ表示主に開発したクラス・メソッドのみを表示します。(.NET Frameworkの一部の型が非表示になる。)
    4小さいオブジェクトの種類を折りたたむヒープサイズ全体の0.5%未満のものを非表示にします。(非表示になったオブジェクトのサイズは、親となるオブジェクトのサイズに含まれるようになります。)
    5停止しているオブジェクトを表示するアプリの参照から外れたオブジェクトを表示します。
    6世代ガベージコレクション(GC)で管理している世代で絞り込んで表示します。(第0世代、第1世代、第2世代、ラージオブジェクト、固定されたオブジェクトヒープ)
    7オブジェクトの種類名前空間を含むオブジェクトのクラス名を表示します。
    8カウント
    サイズ(バイト)
    包括サイズ(バイト)
    カウントとサイズは、そのオブジェクトの数と合計サイズです。包含サイズは、そのオブジェクト群の参照先も含めたサイズです。
    9数の相違
    サイズの相違(バイト)
    包括サイズの相違(バイト)
    「ベースラインと比較」で比較対象となるスナップショットを選択した場合に表示されます。選択したスナップショットを基準として、増減したオブジェクトのカウント、サイズ、包含サイズです。
    10インスタンスの表示オブジェクトの値や格納しているフィールドの値を表示します。
  • オブジェクト種類一覧で「インスタンスの表示」を選択した場合、次のようにインスタンスの値の内容を表示できます。この機能は、デバッガ統合版かつ、ブレークポイント等で実行が一時停止した後に取得したスナップショットでのみ使用できます。

オブジェクト種類詳細

オブジェクト種類詳細は、「ルートの型」「参照された型」タブで構成されます。

  • 「ルートの型」タブは、選択したオブジェクトを参照しているオブジェクト(参照元)が表示されます。オブジェクト一覧で異常なオブジェクトを見つけた際に、どのオブジェクトで生成・参照されてたかを確認する場合に使用できます。
  • 「参照された型」タブは、選択したオブジェクトが参照しているオブジェクト(参照先)が表示されます。オブジェクト一覧で包含サイズが異常なオブジェクトを見つけた際に、そのオブジェクトが参照しているどのオブジェクトが異常なサイズなのかを確認する場合に使用できます。

起動方法と用途

  • メモリ使用量診断ツール(を含むプロファイリングツール)は、デバッガ統合版とパフォーマンスプロファイラー版があります。
    • デバッガ統合版:デバッグ情報を付与して実行するので、ステップ実行や詳細な情報を取得できるが、メモリ使用量が多く性能が劣化する。
    • パフォーマンスプロファイラー版:デバッグ情報を付与せず実行できるので、稼働環境に近い性能で実行できるが、ステップ実行や詳細な情報の取得ができない。
    比較項目デバッガー統合版パフォーマンス
    プロファイラー版
    処理時間の正確性不正確
    (稼働環境より遅い)
    正確
    (稼働環境に近い)
    ステップ実行
    例外時の一時停止
    不可
    変数値の確認不可
    リリースビルド使用不可使用可
    収集情報の保存不可
    (デバッグ停止後に消失)

    (.diagsessionファイルとして保存可)
  • .diagsessionファイルはVisual Studio 2022で開くことができ、レポートを表示できます。
  • リファレンスを要約すると、次のような使い分けになると思います。
    特に要件や制約がないのであれば、まずはお気軽に使えるデバッガ統合版で分析を行い、何か問題があればパフォーマンスプロファイラー版を使うことをお薦めします。

    • デバッガ統合版
      • とりあえず試してみたい。
      • 事象が発生する操作や処理が絞り込まれており、特定個所でのメモリ使用量を確認したい。
      • ブレークポイントの使用、例外発生時の一時中断を行いたい。
      • 増加したオブジェクトの内容(変数値)まで確認したい。
    • パフォーマンスプロファイラー版
      • 処理性能や処理時間に正確さが求められる。
      • 可能な限り運用環境と同様の条件にしたい。
      • デバッガ統合版だと、処理時間がかかりすぎたり、Visual Studioがメモリ不足になってしまう。
      • 他者との共有、調査結果のエビデンス保持等のために、レポート(収集データ)をファイルとして残したい。

使用方法

デバッガ統合版の場合

  1. 「デバッグ」(F5)、または画面上部の起動プロファイル(「IIS Express」やプロジェクト名)をクリックして、デバッグを開始します。
  2. 既定では、デバッグを開始した際に画面右側に診断ツールウインドウされます。

    • 「スナップショットの作成」をクリックすることで、そのタイミグでのスナップショットを取得できます。
    • 取得したスナップショットのオブジェクト数やヒープサイズのリンクをクリックすることで、画面左側に「スナップショットの詳細レポート」を表示できます。同様に、オブジェクトやヒープサイズの「(相違)」のリンクをクリックすることで、「スナップショットの相違レポート」を表示できます。
    • 診断ツールウインドウが表示されない場合、「デバッグ」-「ウインドウ」-「診断ツールの表示」(Ctrl + Alt + F2)から表示できます。設定を既定から変更すると使用できない場合があります。詳細はリファレンスをご覧ください。

パフォーマンスプロファイラー版の場合

  1. メニューの「デバッグ」-「パフォーマンスプロファイラー」(ALT + F2)をクリックします。
  2. 「使用可能なツール」欄で「メモリ使用量」をクリック(チェック)し、「開始」をクリックします。

    • 「ターゲットの変更」から、「実行中のプロセス」等のように別の対象を選択することもできます。
    • ウインドウ右側にある「すべてのツールの表示」をクリックすることで「適用できないツール」を表示することもできます。
    • 次のように「ソリューション構成がデバッグに設定されています。より正確な結果を得るには、リリース構成に切り替えてください。」の警告が表示される場合、「Release」を選択してください。
  3. 「開始」すると、アプリの起動とデータの収集が開始されます。

    • 必要なタイミングで「スナップショットの作成」をクリックし、スナップショットを取得します。必要なスナップショットの取得が終わったら、「収集の停止」をクリックします。
    • レポートの表示方法はデバッガ統合版と同様です。
    • 「スナップショットの作成」をクリックしてもエラーになり、スナップショットを取得できない場合がありました。私の場合、Visual Studio 2022のバージョンを上げたら解決しました。

参考

.NETオブジェクト割当ツールを使用できない

  • .NETオブジェクト割当ツール(.NET Object Allocation tool)は、ASP.NET/ASP.NET Coreのプロジェクトもサポートしています。
  • パフォーマンスプロファイラーを起動した際に、本来であれば「.NETオブジェクト割当ツール」を選択できるはずなのですが、プロジェクトの起動プロファイルが「IIS Express」の場合は選択できないようです。起動プロファイルが「プロジェクト」(Kestrel)の場合は選択できます。
    (なお、表示できても「メモリ使用量」と同時には使用できず、どちらかしか選択できません。)
  • 起動プロファイルに関しては、次のリファレンスをご覧ください。

使用しているサンプルプロジェクト

説明で使用しているサンプルをgithubで公開しています。
メモリの占有や過剰なメモリ確保を試みるようなページを用意しています。