次の方法で共有


パフォーマンスの問題の特定 (C#、Visual Basic、F#)

この記事では、プロファイル ツールを使用してパフォーマンスの問題を調査し、問題領域を特定する方法について説明します。

ここでは、手順を追って説明するのではなく、プロファイリング ツールを効果的に使用する方法とデータを解釈する方法を示します。 CPU 使用率ツールと同様に、.NET カウンター ツールもパフォーマンス調査の際に有効な手段になります。 興味深いデータを確認したら、他のプロファイル ツールを使用して、より深く調査できます。 ツールの比較については、「使用するパフォーマンス ツール」の記事をご覧ください。

サンプル アプリについて

この記事のスクリーンショットは、シミュレートされたデータベースに対してクエリを実行する ASP.NET アプリに基づいています。 この例は、診断の例に基づいています。

調査を開始する

  • パフォーマンス データの収集時に .NET カウンター メトリックを確認して、調査を開始します。
  • 次に、問題の特定に役立つ追加の分析情報を得るため、CPU 使用率ツール、インストルメンテーション ツールなどの他のプロファイリング ツールのいずれかを使用してトレースを収集することを検討します。

データ コレクションには、次の手順が必要です (ここでは示されています線)。

  • アプリをリリース ビルドに設定します。
  • パフォーマンス プロファイラーから .NET カウンター ツールを選びます (Alt + F2 キー)。 (後の手順には、インストルメンテーション ツールが含まれます。)
  • パフォーマンス プロファイラーからアプリを開始します。

パフォーマンス カウンターをチェックする

アプリの実行中に、.NET カウンター ツールでカウンターを確認します。 最初の調査のため、注意が必要な主要指標を次にいくつか示します。

  • CPU Usage。 このカウンターを見ると、CPU 使用率が高いか低いかでパフォーマンスの問題の有無を確認できます。 これは、特定の種類のパフォーマンスの問題の手がかりになる可能性があります。 例:
    • CPU 使用率が高い場合は、CPU 使用率ツールを使用して、コードを最適化できる可能性がある領域を確認します。 このチュートリアルについては、「コードの最適化に関する初心者向けガイド」を参照してください。
    • CPU 使用率が低い場合は、インストルメンテーション ツールを使用して、ウォール クロック時間に基づく平均の関数実行時間および呼び出し数を確認します。 これは、競合やスレッド プールの枯渇などの問題について確認するのに役立つ場合があります。
  • Allocation Rate。 要求を処理する Web アプリの場合、このレートは概ね安定している必要があります。
  • GC Heap Size。 このカウンターを見ると、メモリ使用量が継続的に増加し、リークする可能性の有無を確認できます。 カウンターが高い場合は、メモリ使用量ツールのいずれかを使用できます。
  • Threadpool Thread Count。 要求を処理する Web アプリの場合、このカウンターを見ると、スレッド数が安定しているか、安定して増加しているかどうかを確認できます。

次に示すのは、CPU Usage が低く、ThreadPool Thread Count が比較的高い場合の例です。

.NET カウンター ツールで示されているカウンターのスクリーンショット。

CPU 使用率が低く、スレッド数が安定して増加している場合、スレッド プールが枯渇している可能性があります。 スレッド プールでは、強制的に新しいスレッドが回転し続けます。 スレッド プールの枯渇は、新しい作業項目の処理に使用できるスレッドがプールにない場合に発生し、多くの場合、アプリケーションの応答が遅くなります。

CPU 使用率が低く、スレッド数が比較的多い場合、スレッド プールが枯渇する可能性があるケースの理論に従って、インストルメンテーション ツールの使用に切り替えます。

呼び出し数とタイミング データを調査する

インストルメンテーション ツールのトレースを見て、スレッドで何が起こっているかをより詳しく調べてみましょう。

診断データを読み込んだら、まず、最上位の分析情報とホット パスが示されている最初の .diagsession レポート ページを調べます。 インストルメンテーション トレースのホット パスには、アプリで関数の実行時間が最も長いコード パスが表示されます。 これらのセクションでは、改善できるパフォーマンスの問題をすばやく特定するのに役立つヒントが提供される場合があります。

収集されたトレースで、レポートの [Open details] (詳細を開く) リンクから、[フレーム グラフ] を選択します。

インストルメンテーション ツールのフレーム グラフのスクリーンショット。

フレーム グラフでは、QueryCustomerDB 関数がアプリの実行時間のかなりの部分を占めていることとが分かります。

QueryCustomerDB 関数を右クリックし、[呼び出しツリーで表示] を選択します。

インストルメンテーション ツールの呼び出しツリーのスクリーンショット。

呼び出しツリー ビューでは、ホット パス (炎のアイコン) に QueryCustomerDB 関数が含まれており、潜在的なパフォーマンスの問題が示されていることが確認できます。

他の関数で費やされた時間に比べて、QueryCustomerDB 関数の Self 値および Avg Self 値が非常高いです。 TotalAvg Total とは異なり、Self 値では他の関数で費やされた時間が除外されるため、パフォーマンスのボトルネックを探すのに適しています。

ヒント

Self 値が高くなく、比較的低い場合は、QueryCustomerDB 関数によって呼び出された実際のクエリを調べたいと思うでしょう。

QueryCustomerDB 関数をダブルクリックして、関数のソース コードを表示します。

public ActionResult<string> QueryCustomerDB()
{

    Task dbTask = QueryCustomerFromDbAsync("Dana");
    return "success:tasksleepwait";
}

少し調査すると、このコードが await を使用せずに非同期 API を呼び出していることが分かります。 これは ThreadPool の枯渇における最も一般的な原因である sync-over-async コード パターンです。これにより、スレッドがブロックされる可能性もあります。

解決するには、await を使用します。

public async Task<ActionResult<string>> TaskAsyncWait()
{
    Customer c = await PretendQueryCustomerFromDbAsync("Dana");
    return "success:taskasyncwait";
}

データベース クエリに関連するパフォーマンスの問題が発生した場合は、データベース ツールを使用して、特定の呼び出しが遅いかどうかを調査できます。 このデータにより、クエリを最適化する機会が示される場合があります。 データベース ツールを使用してパフォーマンスを向上させる方法についてのチュートリアルは、「コードの最適化に関する初級者向けガイド」を参照してください。 データベース ツールは、ADO.NET または Entity Framework Core を使用した .NET Core をサポートします。

Visual Studio で個々のスレッドの動作の視覚化するには、デバッグ中に [並列スタック] ウィンドウを使用できます。 このウィンドウには、個々のスレッドと、待機中のスレッド、待機する際の目的のスレッド、デッドロック状態に関する情報が表示されます。

スレッド プールの枯渇についての詳細は、「ThreadPool の枯渇の検出」を参照してください。

次のステップ

次の記事とブログ投稿では、Visual Studio パフォーマンス ツールの効果的な使用方法を学習するのに役立つ情報を提供しています。