Visual Studio でのメモリ使用量の測定 (C#、Visual Basic、C++、F#)
デバッガー統合 メモリ使用量 診断ツールを使用してデバッグしているときに、メモリ リークと非効率的なメモリを見つけます。 メモリ使用量ツールを使用すると、マネージド メモリ ヒープとネイティブ メモリ ヒープ 1 つ以上の スナップショットを取得して、オブジェクトの種類のメモリ使用量への影響を把握できます。 デバッガーをアタッチせずに、または実行中のアプリをターゲットにして、メモリ使用量を分析することもできます。 詳細については、「リリース ビルドまたはデバッグ ビルドでプロファイリング ツールを実行する」を参照してください。 ニーズに最適なメモリ分析ツールの選択については、「メモリ分析ツールを選択する」を参照してください。
メモリ使用量 ツールでは、いつでもメモリ スナップショットを収集できますが、Visual Studio デバッガーを使用して、パフォーマンスの問題を調査しながらアプリケーションがどのように実行されるかを制御できます。 ブレークポイント、ステップ実行、すべて中断、およびその他のデバッガー アクションを設定すると、最も関連性の高いコード パスにパフォーマンス調査を集中するのに役立ちます。 アプリの実行中にこれらのアクションを実行すると、関心のないコードからのノイズを排除でき、問題の診断にかかる時間を大幅に短縮できます。
重要
デバッガー統合診断ツールは、ASP.NET、ASP.NET Core、ネイティブ/C++ 開発、混合モード (.NET およびネイティブ) アプリなど、Visual Studio での .NET 開発でサポートされています。
このチュートリアルでは、次の操作を行います。
- メモリのスナップショットを取得する
- メモリ使用量データの分析
メモリ使用量 が必要なデータを提供しない場合は、パフォーマンス プロファイラーの他のプロファイリング ツール、役に立つ可能性のあるさまざまな種類の情報を提供します。 多くの場合、アプリケーションのパフォーマンスのボトルネックは、CPU、レンダリング UI、ネットワーク要求時間など、メモリ以外のものによって発生する可能性があります。
手記
カスタム アロケーター サポート ネイティブ メモリ プロファイラーは、実行時に生成された ETW イベント データ 割り当てを収集することによって機能します。 CRT および Windows SDK のアロケーターには、割り当てデータをキャプチャできるようにソース レベルで注釈が付けられます。 独自のアロケーターを記述する場合、新しく割り当てられたヒープ メモリへのポインターを返す関数は、myMalloc の次の例に示すように、__declspec(アロケーター) で修飾できます。
__declspec(allocator) void* myMalloc(size_t size)
メモリ使用量データを収集する
Visual Studio でデバッグするプロジェクトを開き、メモリ使用量の調査を開始する時点でアプリにブレークポイントを設定します。
メモリの問題が疑われる領域がある場合は、メモリの問題が発生する前に最初のブレークポイントを設定します。
ヒント
アプリが頻繁にメモリを割り当て、割り当てを解除するときに関心のある操作のメモリ プロファイルをキャプチャするのは困難な場合があるため、操作の開始時と終了時にブレークポイントを設定して (または操作をステップ実行して)、メモリが変更された正確なポイントを見つけます。
分析するコードの関数または領域の末尾に 2 つ目のブレークポイントを設定します (または、メモリの問題が発生した可能性が発生した後)。
診断ツールの ウィンドウは、オフにしていない限り自動的に表示されます。 ウィンドウを再び表示するには、デバッグ>ウィンドウ>診断ツールを表示をクリックします。
ツール バーにある [ツールの選択] の設定で、[メモリ使用量] を選択します。
[デバッグ] / [デバッグの開始] をクリックします (またはツールバーで [スタート] をクリックするか、F5を押します)。
アプリの読み込みが完了すると、診断ツールの概要ビューが表示されます。
[診断ツールの概要] タブの
手記
メモリ データの収集はネイティブ アプリまたは混合モード アプリのデバッグ パフォーマンスに影響を与える可能性があるため、メモリ スナップショットは既定で無効になっています。 ネイティブ または混合モードのアプリでスナップショットを有効にするには、デバッグ セッションを開始します (ショートカット キー: F5)。 [診断ツール] ウィンドウが表示されたら、[メモリ使用量] タブを選択し、[ヒーププロファイリング] を選択します。
停止 (ショートカット キー: Shift+F5) してデバッグを再開します。
[診断ツールの概要] タブの
手記
メモリ データの収集はネイティブ アプリまたは混合モード アプリのデバッグ パフォーマンスに影響を与える可能性があるため、メモリ スナップショットは既定で無効になっています。 ネイティブ または混合モードのアプリでスナップショットを有効にするには、デバッグ セッションを開始します (ショートカット キー: F5)。 [診断ツール] ウィンドウが表示されたら、[メモリ使用量] タブを選択し、[ヒープ プロファイリング] を選択します。
停止 (ショートカット キー: Shift+F5) してデバッグを再開します。
デバッグ セッションの開始時にスナップショットを取得するには、[メモリ使用量] 概要ツール バーの [スナップショットの作成] 選択します。 (ここにブレークポイントを設定するのにも役立つ場合があります)。
アドバイス
メモリ比較のベースラインを作成するには、デバッグ セッションの開始時にスナップショットを作成することを検討してください。
最初のブレークポイントにヒットするシナリオを実行します。
デバッガーが最初のブレークポイントで一時停止している間に、[スナップショットの作成] をメモリ使用量 の概要ツールバーで選択します。
F5 押して、2 番目のブレークポイントにアプリを実行します。
次に、別のスナップショットを作成します。
この時点で、データの分析を開始できます。
データの収集または表示で問題が発生した場合は、「プロファイリング エラーのトラブルシューティングとの問題の修正」を参照してください。
メモリ使用量データの分析
メモリ使用量の概要テーブルの行には、デバッグ セッション中に作成したスナップショットが一覧表示され、より詳細なビューへのリンクが表示されます。
列の名前は、プロジェクトのプロパティで選択するデバッグ モード (.NET、ネイティブ、または混合 (.NET とネイティブの両方) によって異なります。
Objects (Diff) (.NET) 列または Allocations (Diff) (C++) 列には、スナップショットの作成時に .NET またはネイティブ メモリ内のオブジェクトの数が表示されます。
ヒープ サイズ (差分) 列には、.NET ヒープとネイティブ ヒープ内のバイト数が表示されます
複数のスナップショットを作成した場合、概要テーブルのセルには、行スナップショットと前のスナップショットの間の値の変更が含まれます。
メモリ使用量を分析するには、メモリ使用量の詳細レポートを開くリンクのいずれかをクリックします。
- 現在のスナップショットと前のスナップショットの違いの詳細を表示するには、矢印の左側にある変更リンクを選択します (
)。 赤い矢印はメモリ使用量の増加を示し、緑色の矢印は減少を示します。
ヒント
メモリの問題をより迅速に特定できるように、差分レポートは、全体の数が最も多いオブジェクトの種類 (オブジェクト (Diff) 列の変更リンクをクリック) またはヒープ サイズ全体の中で最も大きくなったオブジェクトの種類 ([ヒープ サイズ (差分)] 列の変更リンク クリック) で並べ替えられます。
選択したスナップショットのみの詳細を表示するには、変更されていないリンクをクリックします。
レポートは別のウィンドウに表示されます。
マネージド型のレポート
メモリ使用量の概要テーブルで、オブジェクト (Diff) セルの現在のリンクを選択します。
手記
.NET コードの場合、ビュー インスタンス アイコン (のインスタンス アイコン) は、デバッガー統合メモリ使用量ツール を使用しているとき、または ヒープ スナップショット を開いて [マネージド メモリのデバッグ] 選択した場合にのみ使用できます。
上部のウィンドウには、スナップショット内の型の数とサイズ (型によって参照されるすべてのオブジェクトのサイズを含む) が表示されます (包括サイズ)。
下のウィンドウの [ルートのパス] ツリーには、上のウィンドウで選択されている型を参照するオブジェクトが表示されます。 .NET ガベージ コレクターは、オブジェクトを参照する最後の型が解放された場合にのみ、オブジェクトのメモリをクリーンアップします。 ルート ツリーへの パスの使用の詳細については、「ルートへのホット パスの分析」を参照してください。
上部のウィンドウには、スナップショット内の型の数とサイズ (型によって参照されるすべてのオブジェクトのサイズを含む) が表示されます (包括サイズ)。
下のウィンドウの [ルートのパス] ツリーには、上のウィンドウで選択されている型を参照するオブジェクトが表示されます。 .NET ガベージ コレクターは、オブジェクトを参照する最後の型が解放された場合にのみ、オブジェクトのメモリをクリーンアップします。
参照型 ツリーには、上部ペインで選択した型によって保持されている参照が表示されます。
参照型 ツリーには、上部ペインで選択した型によって保持されている参照が表示されます。
選択した型のインスタンスを上のウィンドウに表示するには、オブジェクトの種類の横にある [インスタンスの表示] アイコン クリックします。
インスタンス ビューには、選択したオブジェクトのインスタンスが上のウィンドウのスナップショットに表示されます。 [ルート への パス] ウィンドウと [参照先オブジェクトの ] ペインには、選択したインスタンスを参照するオブジェクトと、選択したインスタンスが参照する型が表示されます。 スナップショットが作成された時点でデバッガーが停止すると、[値] セルにマウス ポインターを合わせると、ツール ヒントにオブジェクトの値が表示されます。
インスタンス ビューには、選択したオブジェクトのインスタンスが上のウィンドウのスナップショットに表示されます。 [ルート への パス] ウィンドウと [参照先オブジェクトの ] ペインには、選択したインスタンスを参照するオブジェクトと、選択したインスタンスが参照する型が表示されます。 スナップショットが作成された時点でデバッガーが停止すると、[値] セルにマウス ポインターを合わせると、ツール ヒントにオブジェクトの値が表示されます。
ネイティブ型のレポート
[診断ツール] ウィンドウの [メモリ使用量の概要] テーブルで、割り当て (Diff) または ヒープ サイズ (差分) セルの現在のリンクを選択します。
タイプ ビュー には、スナップショット内の型の数とサイズが表示されます。
スナップショットで選択した種類のオブジェクトに関する情報を表示するには、選択した種類のインスタンス アイコン (
のインスタンス アイコン) を選択します。
インスタンス ビューには、選択した種類の各インスタンスが表示されます。 インスタンスを選択すると、割り当て呼び出し履歴 ペインにインスタンスが作成された呼び出し履歴が表示されます。
[表示モード] リストで [スタック ビュー] を選択すると、選択した種類の割り当てスタックが表示されます。
メモリ使用量の分析情報
マネージド メモリの場合、メモリ分析ツールでは、複数の強力な組み込みの自動分析情報も提供されます。 [マネージド型] レポートで [Insights] タブを選択すると、重複する文字列、スパース配列、イベント ハンドラー リークなどの適用可能な自動分析情報が表示されます。
重複文字列 セクションには、ヒープに複数回割り当てられる文字列の一覧が表示されます。 さらに、このセクションでは、無駄なメモリの合計(インスタンスの数 - 1)が文字列のサイズの倍であることを示します。
スパース配列の セクションには、ほとんどの要素がゼロで満たされている配列が表示されます。これは、パフォーマンスとメモリ使用量の面では非効率的な可能性があります。 メモリ分析ツールは、これらの配列を自動的に検出し、これらのゼロ値のために無駄になっているメモリの量を示します。
Visual Studio 2022 バージョン 17.9 Preview 1 で使用可能な イベント ハンドラー リーク セクションには、あるオブジェクトが別のオブジェクトのイベントをサブスクライブするときに発生する可能性があるメモリ リークが表示されます。 イベントのパブリッシャーがサブスクライバーの存続期間を超えた場合、たとえサブスクライバーへの他の参照がなくても、サブスクライバーは生存し続けます。 これにより、メモリ リークが発生し、未使用のメモリが適切に解放されず、時間の経過と同時にアプリケーションで使用されるメモリが増える可能性があります。
特定の型には、保持しているネイティブ メモリのサイズを決定するために読み取ることができるフィールドが存在することがわかっています。 [Insights] タブには、オブジェクト グラフに偽のネイティブ メモリ ノードが表示されます。これは、UI で認識され、サイズと参照グラフが表示されるように、親オブジェクトによって保持されます。
変更 (差分) レポート
[診断ツール] ウィンドウの [メモリ使用量] タブの概要テーブルのセルにある変更リンクを選択します。
マネージド レポートまたはネイティブ レポートの 比較 一覧でスナップショットを選択します。
変更レポートでは、基本スナップショット値と比較スナップショットの違いを示す列 ((Diff)でマーク) がベース レポートに追加されます。 ネイティブ型ビューの差分レポートの外観を次に示します。
上部のウィンドウには、スナップショット内の型の数とサイズ (型によって参照されるすべてのオブジェクトのサイズを含む) が表示されます (包括サイズ)。
ブログとビデオ
Visual C++ ブログ: Visual C++ 2015 でのメモリ プロファイリング
次の手順
このチュートリアルでは、メモリ使用量データを収集して分析する方法について説明しました。 プロファイラー のツアーを既に完了している場合は、プロファイリング ツールを使用してコードを最適化するための一般的なアプローチについて読んでください。
ケース スタディ: コード の最適化に関する初心者向けガイド
このチュートリアルでは、デバッグ中にメモリ使用量データを収集して分析する方法を学習しました。 パフォーマンス プロファイラーを使用したリリース ビルドでのメモリ使用量の分析の詳細を確認できます。
パフォーマンス プロファイラー でメモリ使用量を分析する