dotMemory を使ってみる
サンプルアプリケーション | |
このチュートリアルでは、dotMemory を実行してメモリスナップショットを取得する方法を学習します。さらに、dotMemory のユーザーインターフェースと基本的なプロファイリングの概念について簡単に説明します。dotMemory の出発点として、このチュートリアルを検討してください。
基本用語
質問するかもしれません: " メモリスナップショットとは何ですか、なぜ入手する必要がありますか? " これは、dotMemory を使用している間に出くわすいくつかのメモリプロファイリング条件に合意する良い時期です。
メモリの観点から、アプリケーションの作業は、新しいオブジェクトのメモリの連続的な割り当てと、アプリケーションによって使用されなくなったオブジェクトから残されたメモリを解放することから構成されます。オブジェクトは、いわゆるマネージヒープ内で相次いで割り当てられます。これに基づいて、メモリプロファイラが行うことができなければならない 2 つの基本的な操作を行う:
メモリのスナップショットを取得します。スナップショットは管理対象ヒープのインスタントイメージです。各スナップショットには、スナップショットを取得するボタンをクリックした時点でアプリがメモリ内に割り当てたすべてのオブジェクトに関する情報が含まれています。
メモリトラフィック情報を収集します。メモリトラフィックは、2 つのメモリスナップショットの間など、割り当てられたメモリと解放されたメモリの量を示します。この情報は、アプリケーションがどのように動作するかのダイナミクスを理解することを可能にするため非常に貴重です。
トラフィックを収集してスナップショットを取得する(つまり、アプリケーションのプロファイルを作成する)期間は、プロファイリングセッションと呼ばれます。
もちろん、このチュートリアルに従っている間に知り合う他のいくつかの用語があります。しかし、今のところ、これは次のいくつかのステップで何が起こっているのかを理解するのに十分です。始めましょう !
サンプルアプリケーション
まず、プロファイリング用のアプリケーションが必要です。dotMemory チュートリアルのシリーズ全体を通して、同じ C# アプリケーションを使用します。これは、ほとんどの人がおそらく知っている古典的なコンウェイのライフゲームをエミュレートします。そうでない場合は、ウィキペディア(英語)を確認してください。これにはそれほど時間はかかりませんが、チュートリアルの理解がはるかに簡単になります。開始する前に、github(英語) からアプリケーションをダウンロードしてください。
ステップ 1. dotMemory を実行
Windows のスタートメニューを使用して dotMemory を実行します。
これによりメインの dotMemory ウィンドウが開きます。
次に、プロファイリングセッション(dotMemory がメモリ使用量データを収集する時間枠)を開始しましょう。
左側のパネルでローカルを選択し、プロファイル適用でスタンドアロンアプリケーションを選択します。
これで、プロファイリングセッションオプションを設定する必要があります。右のパネルでは:
アプリケーションで、Game ofLife 実行可能ファイルへのパスを指定します。アプリケーションのリリースビルドをプロファイリングすることをお勧めします *.
開始からメモリ割り当てとトラフィックデータを収集するオプションを選択します。これは、アプリケーションの起動直後に dotMemory に割り当て呼び出しスタックデータの収集を開始するよう指示します。
以下は、すべてのオプションを指定した後のウィンドウの外観です。
プロファイリングセッションを開始するには、実行をクリックします。これは私たちのアプリを実行し、dotMemory の新しい分析タブを開きます。
ステップ 2. スナップショットを取得する
アプリケーションが起動すると、メモリスナップショットを取得できます。この作業の中で最も重要なのは、そのための正しい瞬間を選ぶことです。覚えているように、スナップショットは、アプリケーションの管理されたヒープのインスタントイメージです。スナップショットを撮る前に最初にすべきことは、興味を持っている状態にアプリケーションを持っていくことです。例: Game of Life が立ち上げられた直後に作成されたオブジェクトを見たい場合は、アプリでアクションを実行する前にスナップショットを作成します。逆に、どのオブジェクトが動的に作成されるかを知る必要がある場合は、アプリケーションで開始をクリックした後でスナップショットを作成する必要があります。
Game of Life が実行されているときに割り当てられたオブジェクトに関する情報を取得する必要があると仮定しましょう。アプリケーションの開始ボタンをクリックしてゲームをしばらく実行してください。
dotMemory のスナップショットを取得するボタンをクリックします。
これによりデータがキャプチャーされ、スナップショット領域にスナップショットが追加されます。スナップショットを取得してもプロファイリングプロセスが中断されないため、別のスナップショットを取得できます(今は必要ありません)。
Game of Life ウィンドウを閉じてプロファイリングセッションを終了します。
dotMemory を参照してください。メインページには、撮影した単一のスナップショットと基本情報が含まれるようになりました。
114.47 合計 MB は、アプリケーションが合計 114.47 MB のメモリを消費することを意味します。このサイズは、Windows タスクマネージャーのコミットサイズ(プロセスによって要求されたメモリの量)と同じです。合計値は次のもので構成されます。
非管理メモリ: 管理されたヒープの外部に割り当てられ、ガベージコレクタによって管理されていないメモリ。一般に、これは .NET CLR、ダイナミックライブラリ、グラフィックスバッファ(特にグラフィックスを集中的に使用する WPF アプリケーションの場合)に必要なメモリです。この部分のメモリはプロファイラで解析できません。
。合計額 : 空きメモリを含む管理対象ヒープ内のメモリの総量(要求されたがアプリケーションによって使用されていない)。
使用される .NET : アプリケーションによって使用される管理対象ヒープ内のメモリ量。これは、.NET で作業できるメモリの一部です。このため、プロファイラーで分析できるのはこれだけです。
詳細はスナップショットを見てみましょう。これを行うには、スナップショット #1 リンクをクリックします。
ステップ 3. スナップショットの概要を理解する
スナップショットを開いた後に最初に表示されるのは、インスペクションビューです。このページには、メインスナップショットのホットスポットが表示されます。
ここに見るもの:
最大サイズ : このダイアグラムは、メモリの大部分を消費するオブジェクトの種類を示しています。
最大保持サイズ : ダイアグラムには、キーオブジェクト、つまりアプリケーション内の他のすべてのオブジェクトをメモリに保持しているオブジェクトが表示されます(このチュートリアルの後半の詳細について)。
文字列重複、スパース配列、イベントハンドラーのリークなど: あなたの生活を楽にするために、dotMemory は最も一般的なタイプのメモリの問題についてスナップショットを自動的にチェックします。どこから始めればよいかわからない場合は、これらの自動インスペクションの結果が適切なエントリポイントになります。
ヒープフラグメンテーション : このダイアグラムは、管理対象ヒープセグメント第 1 世代、2、ラージオブジェクトヒープの断片化を示しています。
スナップショットを調べて、スナップショットに含まれるオブジェクトを表示してみましょう。
タイプボタンをクリックします。これにより、スナップショット内のすべてのオブジェクトがタイプ別にグループ化され、タイプビューが表示されます。
dotMemory ユーザーインターフェースとメモリ解析全体のことを知るのに最適な時期です。
ステップ 4. メモリ分析入門書
もう少し先に進む前に、オブジェクトがメモリにどのように格納されているかを少し迂回して話しましょう。これは、dotMemory が実際にあなたに示すものをよりよく理解するために必要です。
メモリ内のオブジェクト
アプリケーションによって消費されるメモリの大部分は、アプリケーションのオブジェクトに割り当てられます。オブジェクトはデータを格納し、他のオブジェクトを参照します。オブジェクトとその参照は、オブジェクトグラフを構成します。例: Photo
クラスのオブジェクトは、long
値型の id
フィールドをそれ自体で格納し、他のフィールド(参照型のオブジェクト)を参照します。
アプリのルート
アプリケーションでメモリが必要になると、.NET のガベージコレクタ(GC)が、不要になったオブジェクトを特定して削除します。これを行うために、GC は、ルート * で始まる各オブジェクトのグラフ、つまり静的フィールド、ローカル変数、外部ハンドルを渡します。オブジェクトがどのルートからも到達できない場合、そのオブジェクトは不要であると見なされ、メモリから削除されます。以下の例では、オブジェクト D と F は、アプリケーションのルートからアクセスできないため、メモリから削除されます。
保持
ここで、保持の重要な概念に到達します。
ルートからオブジェクトへのパスは、他の多くのオブジェクトを経由する場合があります。オブジェクト B へのすべてのパスがオブジェクト A を通過する場合、A は B のドミネーターです。つまり、B は A によって排他的にメモリに保持されます。A がガベージコレクションされると、B もガベージコレクションされます。そのため、各オブジェクトの最も重要なパラメーターは、保持するオブジェクトのサイズです。dotMemory では、このパラメーターは保持されたバイト数と呼ばれます。たとえば、以下の例のオブジェクト C は 632 バイトを保持します。オブジェクト B は C によって排他的に保持されるわけではありません。計算には含まれません。
dotMemory に戻って、開いたタイプビューを見てみましょう。現在、このビューには、ヒープ内のすべてのオブジェクトが、排他的に保持されているメモリの量によって並べ替えられて表示されます。ご覧のとおり、主要部分は System.Windows.Shapes.Ellipse
クラスによって保持されています (どうやら、これらはゲームオブライフのセルを視覚化するために使用する省略記号形です)。このタイプのオブジェクトは、11,864,580 バイトのメモリを保持しますが、それ自体で 3,862,600 バイトを消費します。
主なプロファイリング用語に慣れたら、dotMemory でどのように作業できるかを見てみましょう。
ステップ 5. ユーザーインターフェースに精通する
dotMemory でのあなたの作業を、ある種の犯罪捜査(dotMemory に関する記憶分析)として考えてほしい。ここでの主なアイデアは、データ(1 つ以上のメモリスナップショット)を収集し、多数の容疑者(問題を引き起こしている可能性のある分析対象)を選択することです。容疑者のリストから始めて、このリストを徐々に絞り込みます。ある容疑者は、有罪と判断するまで、あなたを別の容疑者に導く可能性があります。
dotMemory ウィンドウの左側を参照してください。すべての調査手順が示されているのは分析パスです。
分析パスの各項目は分析するサブジェクトです。ご覧のとおり、GameOfLife.exe のプロファイリングから始め(ステップ #1)、次にスナップショット #1 を開き(ステップ #2)、dotMemory にヒープ内のすべてのオブジェクトを表示するように依頼しました(オブジェクトセットすべてのオブジェクト)。小さなアプリでも多数のオブジェクトを作成するため、各オブジェクトを個別に分析する試みはそれほど効果的ではありません。dotMemory におけるあなたの分析の主なサブジェクトがいわゆるオブジェクトセットであるのはそのためです。
オブジェクトセットは、特定の条件によって選択されたオブジェクトの数です。理解しやすいように、何らかのクエリ * (SQL クエリに非常に似ています) の結果としてのオブジェクトセットを考えます。例: dotMemory に、「SomeCall() によって作成され、Gen 2 に昇格されたすべてのオブジェクトを選択する」、または「インスタンス A によってメモリに保持されているすべてのオブジェクトを選択する」などと指示できます。
各オブジェクトセットは、ビューと呼ばれるさまざまな観点からインスペクションできます。画面を参照してください。表示されているビューはタイプと呼ばれ、セット内のオブジェクトがタイプ別にグループ化された単純なリストを表示します。他のビューでは、選択したセットに関するその他の情報を表示できます。たとえば、ドミネータービューでは、選択したオブジェクトをメモリに保持しているユーザーが表示され、呼び出しツリーでは、オブジェクトを作成した呼び出しが表示されます。画面上部のボタンを使用して、ビューを簡単に変更できます。
上記のように、分析した各科目はあなたを別の科目に導くかもしれません。例:
System.Windows.Shapes.Ellipse
クラスはメモリの大部分を保持しており、これらの省略記号をどのような方法で作成したのか知りたい。これを見つけよう。System.Windows.Shapes.Ellipse をダブルクリックするか、これらのオブジェクトのコンテキストメニュー(右クリック)を開き、このオブジェクトセットを開くを選択します。
バックトレースビューを選択します。
ビューは、私たちの省略記号が
Grid.InitCellsVisuals()
メソッドに由来することを示しています。解析パスにもう 1 つのステップ System.Windows.Shapes.Ellipse 型でグループ化するが含まれていることに注意してください。dotMemory を少し試してみてください。例: System.Windows.Shapes.Ellipse クラスのオブジェクトによって保持される内容を決定します。
関連ページ:
使い方
この章では、dotMemory を使い始めるのに役立ちます。次のセクションでは、dotMemory の最初の手順について説明します。dotMemory を使ってみるへの道、メモリリークを見つけるへの道、メモリトラフィックを最適化するへの道、一般的な dotMemory 使用シナリオの詳細については、次のセクションを参照してください。プロファイルスタンドアロンアプリケーションへの道、プロファイル実行プロセスへの道、IISExpress のプロファイル Web アプリケーションへの道、IIS サーバー...
メモリリークを見つける
サンプルアプリケーション人生ゲーム、このチュートリアルでは、dotMemory を使用してアプリケーションでメモリリークを見つけて修正する方法を説明します。しかし、前に進む前に、メモリリークが何であるかに同意しましょう。メモリリークとは何ですか? :最も一般的な定義によれば、メモリリークは、「オブジェクトがメモリに格納されているが、実行中のコードからアクセスできない」という誤ったメモリ管理の結果です。さらに、「メモリリークは時間とともに増加し、クリーンアップされなければシステムは最終的にメモリ不...