Visual Studio でのメモリ使用量の測定 (C#、Visual Basic、C++、F#)

デバッガーに統合された メモリ使用量 診断ツールを使用したデバッグ中に、メモリ リークおよび非効率的なメモリを見つけます。 メモリ使用量ツールを使うと、マネージド メモリ ヒープとネイティブ メモリ ヒープの 1 つまたは複数の "スナップショット" を取得して、オブジェクト型のメモリ使用量への影響を理解するのに役立てることができます。 デバッガーがアタッチされていない状態で、または実行中のアプリをターゲットにして、メモリ使用率を分析することもできます。 詳細については、「デバッガーを使用して、または使用せずにプロファイリング ツールを実行する」を参照してください。 ニーズに最適なメモリ分析ツールを選択する方法については、「メモリ分析ツールの選択」を参照してください。

メモリ使用量 ツールでメモリのスナップショットをいつでも収集できますが、Visual Studio デバッガーを使用すると、パフォーマンスの問題を調査中にアプリケーションの実行方法を制御することができます。 ブレークポイントの設定、ステップ実行、すべて中断、その他のデバッガー アクションは、パフォーマンスの調査を最も関連性の高いコード パスに集中させるのに役立ちます。 アプリの実行中にこれらのアクションを実行することで、目的としていないコードからのノイズを除去することができ、問題の診断にかかる時間を大幅に短縮できます。

重要

デバッガーが統合された診断ツールは、Visual Studio の .NET 開発 (ASP.NET や ASP.NET Core など)、ネイティブ/C++ 開発、混合モード (.NET とネイティブ) アプリで利用できます。 Windows 8 以降では、デバッガーを使用してプロファイル ツールを実行する必要があります ( [診断ツール] ウィンドウ)。

このチュートリアルでは、次の作業を行います。

  • メモリのスナップショットの作成
  • メモリ使用量データの分析

メモリ使用率 では必要なデータを得ることができない場合、パフォーマンス プロファイラーの他のプロファイリング ツールが別の種類の情報を提供します。その情報が役に立つ可能性があります。 多くの場合、アプリケーションのパフォーマンス上の問題は、CPU、UI のレンダリング、ネットワークの要求時間など、メモリ以外の何かが原因になります。

注意

カスタム アロケーター サポート ネイティブ メモリ プロファイラーは、実行時に生成された割り当て ETW イベント データを収集して機能します。 CRT および Windows SDK のアロケーターには、割り当てデータをキャプチャできるように、ソース レベルで注釈が付けられています。 独自のアロケーターを作成する場合、新しく割り当てられたヒープ メモリへのポインターを返すすべての関数は、__declspec(アロケーター) で修飾できます。myMalloc での例を次に示します。

__declspec(allocator) void* myMalloc(size_t size)

メモリ使用量データの収集

  1. Visual Studio でデバッグするプロジェクトを開き、メモリ使用率を調べ始めるポイントでアプリのブレークポイントを設定します。

    メモリの問題があると疑われる領域がある場合は、メモリの問題が発生する前に、最初のブレークポイントを設定します。

    ヒント

    アプリがメモリの割り当てと割り当て解除を頻繁に行う場合、目的とする操作のメモリ プロファイルを取得するのが容易ではないため、操作の最初と最後にブレークポイントを設定して (または操作をステップ実行して)、メモリが変更された正確なポイントを見つけます。

  2. 分析するコードの関数またはリージョンの終わりに (または疑わしいメモリの問題が発生したあとに) 2 つ目のブレークポイントを設定します。

  3. [診断ツール] ウィンドウは、オフにしていない限り自動的に表示されます。 もう一度ウィンドウを表示するには、 [デバッグ] > [ウィンドウ] > [診断ツールの表示] の順にクリックします。

  4. ツールバーにある [ツールの選択] の設定で、 [メモリ使用量] を選択します。

    診断ツールのスクリーンショット。

    診断ツールのスクリーンショット。

  5. [デバッグ]、[デバッグの開始] の順にクリックします (あるいは、ツール バーの [開始] をクリックするか、F5 を押します)。

    アプリケーションが読み込みを完了すると、診断ツールの概要ビューが表示されます。

    診断ツールの [概要] タブのスクリーンショット。

    注意

    メモリ データの収集はネイティブ アプリや混在モードのアプリのパフォーマンスに影響する可能性があるため、既定でメモリのスナップショットは無効になっています。 ネイティブ アプリや混在モードのアプリのスナップショットを有効にするには、デバッグ セッションを開始します (ショートカット キー: F5)。 [診断ツール] ウィンドウが表示されたら、 [メモリ使用量] タブ、 [ヒープのプロファイル] の順に選択します。

    スナップショットの有効化のスクリーンショット。

    デバッグを停止 (ショートカット キー: Shift+F5) してから再開します。

    診断ツールの [概要] タブのスクリーンショット。

    注意

    メモリ データの収集はネイティブ アプリや混在モードのアプリのパフォーマンスに影響する可能性があるため、既定でメモリのスナップショットは無効になっています。 ネイティブ アプリや混在モードのアプリのスナップショットを有効にするには、デバッグ セッションを開始します (ショートカット キー: F5)。 [診断ツール] ウィンドウが表示されたら、 [メモリ使用量] タブ、 [ヒープのプロファイル] の順に選択します。

    スナップショットの有効化のスクリーンショット。

    デバッグを停止 (ショートカット キー: Shift+F5) してから再開します。

  6. デバッグ セッションの開始時にスナップショットを取得するには、 [メモリ使用量] 概要ツールバーで [スナップショットの取得] を選択します。 (ここにもブレークポイントを設定すると役に立つ場合があります。)

    [スナップショットの取得] ボタンのスクリーンショット。

    [スナップショットの取得] ボタンのスクリーンショット。

    ヒント

    メモリ比較のベースラインを作成するには、デバッグ セッションの開始時に、スナップショットを取得することを検討します。

  7. 最初のブレークポイントにヒットするシナリオを実行します。

  8. デバッガーが最初のブレークポイントで一時停止している間に、 [メモリ使用量] 概要ツールバーで [スナップショットの取得] を選択します。

  9. F5 キーを押すと、アプリケーションが 2 つ目のブレークポイントまで実行されます。

  10. 次に、別のスナップショットを取得しましょう。

    この時点で、データの分析を開始できます。

メモリ使用量データの分析

メモリ使用量の概要テーブルの行には、デバッグ セッション中に取得したスナップショットが一覧表示され、より詳細なビューへのリンクが提供されています。

[メモリ使用量] テーブルのスクリーンショット。

[メモリ使用量] テーブルのスクリーンショット。

列の名前は、プロジェクトのプロパティで選択したデバッグ モード (.NET、ネイティブ、または混合 (.NET とネイティブの両方)) によって決まります。

  • [オブジェクト (相違)] および [割り当て (相違)] 列には、スナップショット取得時の .NET メモリおよびネイティブ メモリ内のオブジェクト数が表示されます。

  • [ヒープ サイズ (相違)] 列には、.NET ヒープおよびネイティブ ヒープのバイト数が表示されます。

複数のスナップショットを取得した場合、概要テーブルのセルには、行のスナップショットと前のスナップショットの間の値の変化が含まれます。

メモリ使用量を分析するには、リンクを 1 つクリックして、メモリ使用量の詳細なレポートを開きます。

  • 現在のスナップショットと前のスナップショットの相違点の詳細を表示するには、矢印の左にある変更リンクを選択します (メモリ使用量増加)。 赤い矢印はメモリ使用量が増加したことを示し、緑の矢印は減少したことを示しています。

ヒント

より迅速にメモリの問題を識別するために、Diff レポートは、総数が最も増加したオブジェクト型の順 ( [オブジェクト (相違)] 列の変更リンクをクリック) や、総ヒープ サイズが最も増加したオブジェクト型の順 ( [ヒープ サイズ (相違)] 変更リンクをクリック) に並べ替えられています。

  • 選択したスナップショットのみの詳細を表示するには、変更リンクではないリンクをクリックします。

    レポートが新しいウィンドウに表示されます。

マネージド型レポート

メモリ使用量の概要テーブルで、 [オブジェクト (相違)] または [割り当て (相違)] セルの現在のリンクを選択します。

マネージド型レポートのスクリーンショット。

マネージド型レポートのスクリーンショット。

上のウィンドウには、型で参照されているすべてのオブジェクトのサイズ (包括サイズ) を含む、スナップショット内の型の総数およびサイズが表示されます。

下のウィンドウの [ルートのパス] ツリーには、上ウィンドウで選択されている型を参照するオブジェクトが表示されます。 オブジェクトを参照する最後の型が解放されたときにのみ、.NET のガベージ コレクターによってそのメモリがクリーンアップされます。

[参照されるオブジェクト] ツリーには、上のウィンドウで選択されている型に保持されている参照が表示されます。

参照されるオブジェクトのレポートのスクリーンショット。

[参照される型] ツリーには、上のウィンドウで選択されている型に保持されている参照が表示されます。

参照されるオブジェクトのレポートのスクリーンショット。

上のウィンドウで選択した型のインスタンスを表示するには、[オブジェクト型] の横にある [インスタンスの表示] をクリックします。

メモリ使用量ツールのインスタンス ビューのスクリーンショット。

メモリ使用量ツールのインスタンス ビューのスクリーンショット。

[インスタンス] ビューには、上のウィンドウのスナップショットで選択されているインスタンスが表示されます。 [ルートのパス] および [参照されたオブジェクト] ウィンドウには、選択したインスタンスを参照するオブジェクト、および選択したインスタンスで参照される型が表示されます。 スナップショットが取得された時点でデバッガーを停止すると、 [値] セルの上にマウス カーソルを移動して、ツール ヒントにオブジェクトの値を表示することができます。

ネイティブ型のレポート

[診断ツール] ウィンドウのメモリ使用量の概要テーブルで、 [割り当て (相違)] または [ヒープ サイズ (相違)] セルの現在のリンクを選択します。

ネイティブ型ビューのスクリーンショット。

ネイティブ型ビューのスクリーンショット。

[型ビュー] には、スナップショットの型の数およびサイズが表示されます。

  • 選択した型のインスタンス アイコン ([オブジェクト型] 列の [インスタンス] アイコン) を選択し、スナップショットの選択した型のオブジェクトに関する情報を表示します。

    [インスタンス] ビューには、選択した型の各インスタンスが表示されます。 インスタンスを選択すると呼び出し履歴が表示され、その結果、 [割り当て呼び出し履歴] ウィンドウにそのインスタンスが作成されます。

    インスタンス ビューと割り当て呼び出し履歴ウィンドウのスクリーンショット。

  • 選択した型の横にある [インスタンスの表示] を選択し、スナップショットの選択した型のオブジェクトに関する情報を表示します。

    [インスタンス] ビューには、選択した型の各インスタンスが表示されます。 インスタンスを選択すると呼び出し履歴が表示され、その結果、 [割り当て呼び出し履歴] ウィンドウにそのインスタンスが作成されます。

    インスタンス ビューと割り当て呼び出し履歴ウィンドウのスクリーンショット。

  • [表示モード] の一覧で [スタック ビュー] を選択し、選択した型の割り当て履歴を表示します。

    [スタック] ビューのスクリーンショット。

  • [スタック] を選択して、選択した型の割り当て履歴を表示します。

    [スタック] ビューのスクリーンショット。

変更 (Diff) レポート

  • [診断ツール] ウィンドウの [メモリ使用量] タブで、概要テーブルのセルにある変更リンクを選択します。

    セル内の変更リンクを選択しているスクリーンショット。

    セル内の変更リンクを選択しているスクリーンショット。

  • マネージド レポート、もしくはネイティブ レポートの [比較対象] 一覧でスナップショットを選択します。

    比較対象の一覧からスナップショットを選択しているスクリーンショット。

    比較対象の一覧からスナップショットを選択しているスクリーンショット。

変更レポートを実行すると、基本のスナップショット値と比較のスナップショットの差分を表示する列 ( (Diff) のマークが付けられる) が、基本レポートに追加されます。 ネイティブ型の差分レポート ビューは次のようになります。

ネイティブ型の差分ビューのスクリーンショット。

ネイティブ型の差分ビューのスクリーンショット。

ブログとビデオ

デバッグ中に CPU とメモリを分析する

Visual C++ ブログ:Visual C++ 2015 のメモリ プロファイル

次の手順

このチュートリアルでは、メモリ使用量データを収集し、分析する方法について学習しました。 プロファイラーのツアーを既に完了している場合、自分のアプリの CPU 使用量を分析する方法を一読しておくことをお勧めします。