連載
.NET&Windows Vistaへ広がるDirectXの世界

第6回 .NETアプリを軽快にするためのガベージ・コレクション講座

NyaRuRu
Microsoft MVP Windows - DirectX(Jan 2004 - Dec 2007)
2007/02/13
Page1 Page2 Page3 Page4

.NET CLRのモニタリング方法

 .NET CLRには、GCの動作を観察するためのさまざまな手段が提供されている。Windowsで動かすXNAゲームは、単なる.NETアプリケーションであるため、以前から知られているこれらの手法をそのまま適用することが可能だ(Xbox 360上で実行するXNAゲームのプロファイリング方法については、後ほどあらためて紹介する)。

 まずは、.NET CLRにどのようなモニタリング方法があるか見ていくことにしよう。

簡単に状況を把握できるパフォーマンス・カウンタ

 ソース・コードに修正を加えることなく手軽に簡単にGCの状況を把握するには、パフォーマンス・カウンタが便利だ。

 Windows OSにパフォーマンス・カウンタという統一的なプロファイリングの仕組みが存在することは、開発者のみならずIT管理者にもおなじみだろう。.NET Frameworkをインストールすると、.NET CLRに関する多くのカウンタが追加される。この中に、GCの内部統計値を公開するカウンタが存在する。カテゴリ「.NET CLR Memory」内のカウンタがそれに当たる。各カウンタの正常範囲については、先ほど資料として挙げたCLRとマネージ コードが参考になる。

 パフォーマンス・カウンタをモニタするのに便利なソフトウェアもいくつか紹介しておこう。

【無償提供されているツール】

  • OS付属のパフォーマンス・カウンタ・モニタ
     コントロール・パネルの「管理ツール」内に、パフォーマンス・カウンタのモニタ・ツールが存在する。ただし大量のカウンタをモニタするのにはあまり向いていない。

  • Process Explorer
     有名なProcess Explorerも、プロセスごとに.NET関連のパフォーマンス・カウンタをモニタする機能がある。こちらもたくさんのカウンタを並べるのには向いていないため、「% Time in GC」や「Allocated Bytes/sec」など一目見て現在の状況が理解しやすいカウンタを表示させておくとよいだろう。

  • PIX for Windows
     第4回で紹介したDirect3D向けのプロファイリング・ツールであるPIX for Windowsも、パフォーマンス・カウンタのモニタ用に使用することができる。ゲーム中のイベントや3D処理との相関をモニタするのに有用だろう。

【有償提供されているツール】

  • Intel VTune
     ネイティブ・アプリケーションのプロファイリング・ツールとして有名なIntel社のVTuneも、パフォーマンス・カウンタのモニタ機能を持っている。

  • PowerGadgets(+PowerShell)
     PowerGadgets社の提供するPowerShell向け可視化ガジェットであるPowerGadgetsは、パフォーマンス・カウンタのような数値データのモニタで有用だ。

プログラムからGC情報にアクセスする

 System名前空間のGCクラスは、GCに関する情報の取得にも使用できる。

 GCクラスには普段あまりお世話になることがないかもしれないが、実はGCの発生回数やオブジェクトの世代を調べるメソッドが存在する。アプリケーション中のさまざまなオブジェクトの世代をモニタリングしてみることで、新たな発見があるかもしれない。

  • GC.CollectionCount(int generation) メソッド
     ある世代のGCが何回行われたかが返される。なお、このメソッドは.NET Compact Framework(以下.NET CF)ではサポートされていない。

  • GC.GetGeneration(Object obj) メソッド
     指定されたオブジェクトの世代が返される。.NET CFではサポートされていない。

  • GC.MaxGeneration プロパティ
     システムがサポートする最大の世代数が返される。.NET CFではサポートされていない。

オブジェクトの寿命や、GCヒープの中を見る

 より詳細にGCとオブジェクトの寿命を見るために、デバッガやデバッグAPIを使用する方法がある。ツールを用いて現象を可視化することで、よりその理解が深まることだろう。

  • CLR Profiler 2.0
     マイクロソフトによって無償提供されているCLR Profilerは、CLRのDebug APIを利用して動くプロファイラだ。GCに関するプロファイリングに応用する方法は、Patterns and Practices「How To 情報: CLR プロファイラの使用方法」で詳しく解説されている。ソース・コードも付属しており、CLR Debug APIを使用して、より詳細なプロファイリングを行うための良い教材にもなるだろう。

  • Visual Studio Team System for Team Developer付属のCode Profiler
     Visual Studio Team System for Team Developerに付属するプロファイラも、オブジェクトの割り当て量や生存期間をモニタするのに使用できる。

  • Son of Strike(sos.dll)
     .NET Frameworkに付属するsos.dllを使用すると、デバッガからCLRの内部情報にアクセスすることができる。アクセス可能な情報の中にはGCヒープに関するものもあり、GCの調査では有用である。テキスト・ベースで可視化には向いていないが、数値による正確な情報を知ることのできる方法だ。
     sos.dllを使用するには、主に2通りの方法がある。1つはVisual Studioから使用する方法だが、これはエディションによって制限があることに注意が必要だ。詳しくはMSDNの資料「SOS を使用する」を参照されたい。
     もう1つの方法はDebugging Tools for Windows(無償)に付属するWinDbgと組み合わせるというもので、sos.dllのすべての機能を使用するにはこちらの方法を使用することになる。
     sos.dllの使用法としては、先ほど紹介したProduction Debugging for .NET Framework Applicationsが参考になる。また、コマンド一覧が「SOS Debugging Extension (SOS.dll)」で公開されている。

  • dotTrace 2.0
     Visual Studio向けの強力なアドインReSharperを提供していることで有名なJetBrains社が、.NET向けのプロファイラとして提供しているのがdotTraceだ。

XNAによるクロス開発とGCの違い

 さて、ここからはXNAによるゲーム・プログラミングを仮定して、GCがどのように影響してくるか考えてみよう。

 CLRは、Common Language Interface(CLI)のマイクロソフトによる実装の1つである。CLRには、.NET Frameworkに付属するもの(以下.NET CLR)に加え、スマート・デバイスやモバイル機器向けの.NET Compact Frameworkに付属するCLR(以下.NET CF CLR)といった派生版が存在する。

 第4回の記事で述べたように、XNAで使用されるXbox 360用のCLR(以下Xbox 360 CLR)は、.NET Compact Frameworkチームの協力のもと、.NET CF CLRをベースにカスタマイズされたものである(詳細については、XNAドキュメントの「.NET Compact Framework for Xbox 360」を参照のこと)。

 実は、この.NET CF CLRのGCアルゴリズムは、以下のように.NET CLRのものと異なっている。

GCアルゴリズム
・.NET CLR (1.x, 2.0) …… 世代別GC*1
・.NET CF CLR (1.x, 2.0) …… マーク&スイープGC*2

 その結果、.NET CF CLR 2.0から派生したXbox 360 CLRも、マーク&スイープGCを使用することになった。従ってXNAによるWindowsとXbox 360とのクロス開発は、ハードウェアの違いだけでなく、CLRの違いからくるGC特性の違いについても検討が必要になる。

*1 世代別GCとは、「オブジェクトの生存期間(=世代)に着目して、新しく若い世代のオブジェクトのメモリを(どこからも参照されていなければ)積極的に収集し、何度もGCで収集されなかった古い世代のオブジェクトのメモリはほとんど回収しない」というアルゴリズムのこと。
*2 マーク&スイープGCとは、「ルート・オブジェクトから(それが参照している)オブジェクトを順にたどって、そのすべてのオブジェクトにマーク(=印)を付けていく。マークが付かなかったオブジェクトは不要なものとしてスイープ(=破棄)する。最後にメモリの断片化を解消してコンパクト化する」というアルゴリズムのこと。

 .NET CF CLRのGCの仕組みについて解説した資料はあまり多くないが、XNAの登場で最近注目されるようになってきた。先ほど紹介した資料と重複するが、MSDN Blogの以下の記事が参考になる。

 これらの記事を参考にすると、.NET CF CLRやXbox 360 CLRのGCは次のような特性を持つということになる。

  • .NET CF CLRやXbox 360 CLRはマーク&スイープGCを利用する。これは1つの世代のみを持つ.NET CLRのGCと似たような特性を持つ

  • 常にメモリのコンパクト化(Compaction:メモリ断片化の解消)が行われる。GCヒープ、つまりヒープ上に作られたオブジェクトの総量がCPUのキャッシュ・メモリと同程度であればよいパフォーマンスを発揮するが、GCヒープが肥大化してくると、パフォーマンスは極端に悪化する

  • Xbox 360 CLRでは、GCヒープから1Mbytesのメモリを確保するごとに、あるいはOutOfMemoryException例外が発生したときにGCが行われる

Xbox 360でのリアルタイムGCモニタリング

 XNA Game Studio Express(以下XNA GSE)には、XNA Remote Performance Monitorと呼ばれるツールが付属しており、Xbox 360上でゲームを動作させながら、Xbox 360 CLRのパフォーマンス・カウンタをリアルタイムにモニタリングできる。

実行中のXNA Remote Performance Monitor
実は、XNA Remote Performance Monitorでモニタリングできるカウンタの種類はWindows上で.NET CLRを動作させたときのものよりも多く、リアルタイム性が重視されるゲーム開発に役立つものが多数追加されている。将来の.NET CLRにも反映させていただきたいぐらいだ。

 使用方法は、XNAドキュメントの「How to: Monitor Performance at Run Time」を参照していただきたい。起動中のゲームにアタッチするのではなく、XNA Remote Performance Monitorからプロファイリング・モードでゲームを起動することになる。表示される各カウンタの意味についてはXNAドキュメントの「Performance Counters in the XNA Framework」でそれぞれ詳しく解説されている。

 いくつか、ゲーム特有の事情についても触れておこう。


 INDEX
  .NET&Windows Vistaへ広がるDirectXの世界
  第6回 .NETアプリを軽快にするためのガベージ・コレクション講座
    1.GCの影響を軽減する必要性
  2.GCがアプリケーションに与える影響
    3.GCの発生頻度を抑えるための対策
    4.値型でGCヒープの消費を抑える
 
インデックス・ページヘ  「.NET&Windows Vistaへ広がるDirectXの世界」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間